花了好多時間建置和測試 C# 的 Serviced Component,測試和建置結果對於企業級的公司有很大的好處,為何呢?要做到3層式(或多層式)架構對企業來說是非常重要的,因為如果企業如果遇到要加新的功能,或 expose 原有的功能到新的 presentation layer (mobile 手機, iPad, 等)那你就一定要把 presentation - business - data , web service etc 等都分開來為不同的 layer,來取得可以改變程式架構的空間,當然複雜度也會增加,但因為不同的部分都會由不同的工程師來負責,所以也可以讓多人同時工作。
市面上 Serviced Component 書很少,不然就是很舊,然後 Microsoft 又一直說要改成 WCF,但根本就一樣概念的東西。。。。只是需要判斷不同的 techonogy 需要在何時情況才用。
好了,不廢話了,直接把結果說出來:
把既有的 business, data component 等 ( C# or vb6 or etc.),放在你已有的地方不要動,多做出一層 ServiceComLayer.cs 把你要 expose的 functions 使用 繼承 ServicedComponent 來 expose 出來給其他的不管是 Delphi, VB6, PHP, classic asp,只要是32-bit window,他都吃。(不用每個 class 繼承 servicedComponent)
我知道你會說,等等,不是要 64-bit 時代了,你還在管 32-bit?
1. 你不可能每次都做新的功能或案子,就不理舊的東西,企業需要延續性
2. 就算是新技術,此確保舊功能(dll 元件)都還可以用,在加上新的功能(技術)時,延伸就好了。因為你的核心已是C# 最新的framework,你只是 expose 給其他技術(或平台)做連接, e.g. PHP也可喔,ASP.NET無敵慢。
3. 連接 third party Component 然後 expose到你現有(32-bit app, vb6 etc) 或新的 C# application都可以。
4. 做成 web service給 application 或網站使用,執行效率太差了~
5. 如何服務 mobile application, 之後我再發表吧。。。。這樣一來,同一套程式,不用寫那麼多次。。。。只要改presentation layer就好了。
如果你覺得沒用,可能你貴公司不是在此企業架構下,就不用想那麼多啦~!
就算是 Wall Street Journal 也還有很多 classic asp (http://chinese.wsj.com/big5/index.asp)頁面,PHP頁面(https://secure.wsj-asia.com/subscription1/index.php),這不是一時三刻改得完,或怎是企業覺得沒有必要去換成新的網頁技術(因為舊的還很好用)。那以上文章可幫助你朝這方向前進。
2013年2月28日 星期四
2012年10月30日 星期二
[C#] 轉換成數字的方法:int.Parse()、int.TryParse()、Convert.ToInt32()
將字串等型態的值轉換成數字是常用到的轉換
不過有時候轉換失敗時
就會產生錯誤
雖然可以用try.....catch去處理例外
不過int.TryParse()更方便
只要轉換失敗
就會傳回false和數字0
這可避免不必要的例外
以下是三種方法的狀況比較
我的用法:
if (int.TryParse(l_sTimeoutText, out l_iTimeout) == false) //判斷tbxTimeout2.Text,字串是否為數字,不是就傳出false,並使用預設值
{ //string轉int
l_iTimeout = 1000; }
Quote reference: 小葛部落格
不過有時候轉換失敗時
就會產生錯誤
雖然可以用try.....catch去處理例外
不過int.TryParse()更方便
只要轉換失敗
就會傳回false和數字0
這可避免不必要的例外
以下是三種方法的狀況比較
//int.Parse各式輸入值的狀況
int.Parse("20"); //20
int.Parse("1000000000000"); //OverflowException
int.Parse("a"); //FormatException
int.Parse(String.Empty); //FormatException
int.Parse(null); //ArgumentNullException
//int.TryParse各式輸入值的狀況
int resultInt = 0;
int.TryParse("20", out resultInt); //True
int.TryParse("1000000000000", out resultInt); //False
int.TryParse("a", out resultInt); //False
int.TryParse(String.Empty, out resultInt); //False
int.TryParse(null, out resultInt); //False
//Convert.ToInt32各式輸入值的狀況
Convert.ToInt32("20"); //True
Convert.ToInt32("1000000000000"); //OverflowException
Convert.ToInt32("a"); //FormatException
Convert.ToInt32(String.Empty); //FormatException
Convert.ToInt32(null); //0
我的用法:
if (int.TryParse(l_sTimeoutText, out l_iTimeout) == false) //判斷tbxTimeout2.Text,字串是否為數字,不是就傳出false,並使用預設值
{ //string轉int
l_iTimeout = 1000; }
Quote reference: 小葛部落格
2012年9月6日 星期四
How to use .Net assemblies in PHP
Quoted from Link
How to use .Net assemblies in PHP
Introduction
For my entry in the WinPHP Challenge I need to use some .Net assemblies I wrote a while ago. It wasn’t clear to me how this can be done. Here’s an example on how to do this. In short: First we create an assembly in visual studio, than we sign it, add it to the Global Assembly Cache or GAC and access it using PHP from there.
Details
Inside visual studio, create a new project. For the purpose of explanation I named the project DotNetTest.
Add the following method to the newly created Class1 class. Make sure the class is declared public.
public class Class1
{
public string SayHello()
{
return "Hello from .NET";
}
}
Now, go ahead an see if this compiles by clicking Build->Build Solution in the menu, or by hitting Ctrl+Alt+B on your keyboard. It may come as no surprise that it does… ;)
To be able to use it thru the GAC the assembly has to be signed. Signing can by done in visual studio. Go to the project properties by right-clicking the project and click Properties all the way at the bottom. Go to the Signing tab. Check theSign the assembly checkbox and select <New…> from the dropdown list beneath that. Give the key file a nice name, like DotNetTestKey and uncheck Protect my key file with a password, because security isn’t an issue in this demo. ClickOk to close the window and finish the signing.
PHP uses COM, even for .NET, we have to make sure the assembly is Com Visible. Go to the Application tab in theProperties windows and click the Assembly Information button. Check the box next to Make assembly COM-Visible and click Ok.
Build the solution again to make sure the assembly we’re about to add to the GAC is signed and configured correctly.
Next, we have to register the assembly in the GAC. The easiest way to do this is thru the command-line. Visual studio provides a short cut to the command prompt by right-clicking on the project in the solution explorer and click Open Command Prompt. Go to the debug folder by typing cd bin/debug. Enter the following command to install the assembly into the GAC:
gacutil -i DotNetTest.dll
The utility should tell you that the assembly as successfully been added to the cache.
Last, take your favorite PHP editor and create a new PHP file with the code below.
<?php
$class1 = new DOTNET("DotNetTest,"
."Version=1.0.0.0,"
."Culture=neutral,"
."PublicKeyToken=????????????????"
,"DotNetTest.Class1");
echo($class1->SayHello());
?>
The DOTNET class instantiates a class from a .Net assembly. The full assembly name must be provided to the constructor at the place of the ‘???’ in the example. This can be found by going to C:\Windows\Assembly using the Windows Explorer or by opening the .dll file in a tool like Reflector.
Place the file at a location accessible thru the browser and go there. If everything went well, it should say “Hello from .Net”
How to write a DCOM server in C#
How to write a DCOM server in C#
18 Jun 2004 5:10 PM
Updated 12/06/2006: http://msdn2.microsoft.com/en-gb/library/system.runtime.interopservices.registrationservices.unregistertypeforcomclients.aspx states that PInvoking CoRegisterClassObject is a technique which is not supported.
Well, why DCOM and not .NET Remoting? For one thing, DCOM offers a secure interprocess communication channel through TCP/IP... which .NET remoting doesn't have unfortunately. Also, a DCOM server can be hosted in almost any process, including Windows Services!
The ideas are described below (this is pretty straightforward assuming you already know COM)
1) Your server process will expose a COM class factory that would just create your .NET object.
2) In COM you register the class factory using the standard CoRegisterClassObjects API
3) Make sure you call CoInitializeSecurity on your first process, for example to allow only Administrators to call in
4) Register your .NET assemblies with REGASM.EXE. Make sure your .NET class is visible through COM so CCW can be created around it (more details in MSDN on COM Interop section).
5) Remove the auto-generated InprocServer32 key after registration (REGASM puts it there but we are going out-of-proc)
6) Add the standard LocalServer32 / AppID registry keys.
That's it! Now you have a secure DCOM service implemented entirely in C# :-)
Here is the C# source code:
The registration CMD script:
And a test VBS script that will exercise our service from a separate process obviously:
One more comment: The code above allows everybody to call into the process. This is probably not very useful since you might want to allow only administrators to call into your service. There is a solution though: all you have to do is to pass a certain security descriptor to CoInitializeSecurity that will allow only certain classes of users to call into the process. This is actually not very hard, and I'll probably post a sample code in the future. Now I have to get back to work, so see you for the next time!
Well, why DCOM and not .NET Remoting? For one thing, DCOM offers a secure interprocess communication channel through TCP/IP... which .NET remoting doesn't have unfortunately. Also, a DCOM server can be hosted in almost any process, including Windows Services!
The ideas are described below (this is pretty straightforward assuming you already know COM)
1) Your server process will expose a COM class factory that would just create your .NET object.
2) In COM you register the class factory using the standard CoRegisterClassObjects API
3) Make sure you call CoInitializeSecurity on your first process, for example to allow only Administrators to call in
4) Register your .NET assemblies with REGASM.EXE. Make sure your .NET class is visible through COM so CCW can be created around it (more details in MSDN on COM Interop section).
5) Remove the auto-generated InprocServer32 key after registration (REGASM puts it there but we are going out-of-proc)
6) Add the standard LocalServer32 / AppID registry keys.
That's it! Now you have a secure DCOM service implemented entirely in C# :-)
Here is the C# source code:
using System;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.ServiceProcess;
using System.Threading;
using System.Runtime.InteropServices;
namespace Test
{
//
// .NET class, interface exposed through DCOM
//
// exposed COM interface
[GuidAttribute(MyService.guidIMyInterface), ComVisible(true)]
public interface IMyInterface
{
string GetDateTime(string prefix);
}
// exposed COM class
[GuidAttribute(MyService.guidMyClass), ComVisible(true)]
public class CMyClass: IMyInterface
{
// Print date & time and the current EXE name
public string GetDateTime(string prefix)
{
Process currentProcess = Process.GetCurrentProcess();
return string.Format("{0}: {1} [server-side COM call executed on {2}]",
prefix, DateTime.Now, currentProcess.MainModule.ModuleName);
}
}
//
// My hosting Windows service
//
internal class MyService :
ServiceBase
{
public MyService()
{
// Initialize COM security
Thread.CurrentThread.ApartmentState = ApartmentState.STA;
UInt32 hResult = ComAPI.CoInitializeSecurity(
IntPtr.Zero, // Add here your Security descriptor
-1,
IntPtr.Zero,
IntPtr.Zero,
ComAPI.RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
ComAPI.RPC_C_IMP_LEVEL_IDENTIFY,
IntPtr.Zero,
ComAPI.EOAC_DISABLE_AAA
| ComAPI.EOAC_SECURE_REFS
| ComAPI.EOAC_NO_CUSTOM_MARSHAL,
IntPtr.Zero);
if (hResult != 0)
throw new ApplicationException(
"CoIntializeSecurity failed" + hResult.ToString("X"));
}
// The main entry point for the process
static void Main()
{
ServiceBase.Run(new ServiceBase[] { new MyService() });
}
///
/// On start, register the COM class factory
///
protected override void OnStart(string[] args)
{
Guid CLSID_MyObject = new Guid(MyService.guidMyClass);
UInt32 hResult = ComAPI.CoRegisterClassObject(
ref CLSID_MyObject,
new MyClassFactory(),
ComAPI.CLSCTX_LOCAL_SERVER,
ComAPI.REGCLS_MULTIPLEUSE,
out _cookie);
if (hResult != 0)
throw new ApplicationException(
"CoRegisterClassObject failed" + hResult.ToString("X"));
}
///
/// On stop, remove the COM class factory registration
///
protected override void OnStop()
{
if (_cookie != 0)
ComAPI.CoRevokeClassObject(_cookie);
}
private int _cookie = 0;
//
// Public constants
//
public const string serviceName = "MyService";
public const string guidIMyInterface = "e88d15a5-0510-4115-9aee-a8421c96decb";
public const string guidMyClass = "f681abd0-41de-46c8-9ed3-d0f4eba19891";
}
//
// Standard installer
//
[RunInstaller(true)]
public class MyServiceInstaller :
System.Configuration.Install.Installer
{
public MyServiceInstaller()
{
processInstaller = new ServiceProcessInstaller();
serviceInstaller = new ServiceInstaller();
// Add a new service running under Local SYSTEM
processInstaller.Account = ServiceAccount.LocalSystem;
serviceInstaller.StartType = ServiceStartMode.Manual;
serviceInstaller.ServiceName = MyService.serviceName;
Installers.Add(serviceInstaller);
Installers.Add(processInstaller);
}
private ServiceInstaller serviceInstaller;
private ServiceProcessInstaller processInstaller;
}
//
// Internal COM Stuff
//
///
/// P/Invoke calls
///
internal class ComAPI
{
[DllImport("OLE32.DLL")]
public static extern UInt32 CoInitializeSecurity(
IntPtr securityDescriptor,
Int32 cAuth,
IntPtr asAuthSvc,
IntPtr reserved,
UInt32 AuthLevel,
UInt32 ImpLevel,
IntPtr pAuthList,
UInt32 Capabilities,
IntPtr reserved3
);
[DllImport ("ole32.dll")]
public static extern UInt32 CoRegisterClassObject (
ref Guid rclsid,
[MarshalAs (UnmanagedType.Interface)]IClassFactory pUnkn,
int dwClsContext,
int flags,
out int lpdwRegister);
[DllImport ("ole32.dll")]
public static extern UInt32 CoRevokeClassObject (int dwRegister);
public const int RPC_C_AUTHN_LEVEL_PKT_PRIVACY = 6; // Encrypted DCOM communication
public const int RPC_C_IMP_LEVEL_IDENTIFY = 2; // No impersonation really required
public const int CLSCTX_LOCAL_SERVER = 4;
public const int REGCLS_MULTIPLEUSE = 1;
public const int EOAC_DISABLE_AAA = 0x1000; // Disable Activate-as-activator
public const int EOAC_NO_CUSTOM_MARSHAL = 0x2000; // Disable custom marshalling
public const int EOAC_SECURE_REFS = 0x2; // Enable secure DCOM references
public const int CLASS_E_NOAGGREGATION = unchecked((int)0x80040110);
public const int E_NOINTERFACE = unchecked((int)0x80004002);
public const string guidIClassFactory = "00000001-0000-0000-C000-000000000046";
public const string guidIUnknown = "00000000-0000-0000-C000-000000000046";
}
///
/// IClassFactory declaration
///
[ComImport (), InterfaceType (ComInterfaceType.InterfaceIsIUnknown),
Guid (ComAPI.guidIClassFactory)]
internal interface IClassFactory
{
[PreserveSig]
int CreateInstance (IntPtr pUnkOuter, ref Guid riid, out IntPtr ppvObject);
[PreserveSig]
int LockServer (bool fLock);
}
///
/// My Class factory implementation
///
internal class MyClassFactory : IClassFactory
{
public int CreateInstance (IntPtr pUnkOuter,
ref Guid riid,
out IntPtr ppvObject)
{
ppvObject = IntPtr.Zero;
if (pUnkOuter != IntPtr.Zero)
Marshal.ThrowExceptionForHR (ComAPI.CLASS_E_NOAGGREGATION);
if (riid == new Guid(MyService.guidIMyInterface)
|| riid == new Guid(ComAPI.guidIUnknown))
{
//
// Create the instance of my .NET object
//
ppvObject = Marshal.GetComInterfaceForObject(
new CMyClass(), typeof(IMyInterface));
}
else
Marshal.ThrowExceptionForHR (ComAPI.E_NOINTERFACE);
return 0;
}
public int LockServer (bool lockIt)
{
return 0;
}
}
}
set EXE_FULL_PATH=%~dp0windowsservice1.exe
if not exist %EXE_FULL_PATH% @echo Executable %EXE_FULL_PATH% not present in the current directory! & @goto :EOF
installutil /u %EXE_FULL_PATH%
installutil %EXE_FULL_PATH%
regasm %EXE_FULL_PATH% /codebase
REG.EXE ADD HKCR\AppID\{9922b97d-ce4a-4cc8-a26f-4944708e652d} /v LocalService /t REG_SZ /d MyService /f
REG.EXE ADD HKCR\CLSID\{F681ABD0-41DE-46C8-9ED3-D0F4EBA19891}\LocalServer32 /ve /t REG_SZ /d %EXE_FULL_PATH% /f
REG.EXE DELETE HKCR\CLSID\{F681ABD0-41DE-46C8-9ED3-D0F4EBA19891}\InprocServer32 /f
Dim obj
Set obj = CreateObject( "Test.CMyClass" )
wscript.echo obj.GetDateTime("Current date: ")
.NET 4 如何使用Assembly dll
馬克吐溫
註冊assembly
如何找到 public key token
--> sn –T myDLL.dll
如何找到你製作 dll 的 public key token? 請記住,你的assembly必須是 strongly signed.
範例:
C:\WINNT\Microsoft.NET\Framework\v3.5>sn -T EdmGen.exe
Microsoft (R) .NET Framework Strong Name Utility Version 3.5.21022.8
Copyright (c) Microsoft Corporation. All rights reserved.
Public key token is b77a5c561934e089
%windir%\Microsoft.NET\assembly\
C#: List 的使用方法,以免每次都忘記還要查
情況一:Add
List<int> list = new List<int>(); list.Add(2); list.Add(3); list.Add(5); list.Add(7);情況二:Loop & Count & clear
List<int> list = new List<int>(); list.Add(2); list.Add(3); list.Add(7); foreach (int prime in list) { Console.WriteLine(prime); } //效能會比 foreach 好 for (int i = 0; i < list.Count; i++){ Console.WriteLine(list[i]); }List.Clear;
情況三:Sort重要!
list.Sort(); 太簡單,不解釋了這比較重要,使用 LINQ 和 sort 的屬性來做排序, 以下是以字長短來排列 List<string> list = new List<string>(); list.Add("mississippi"); // 最長值 list.Add("indus"); list.Add("danube"); list.Add("nile"); // 最短值 var lengths = from element in list orderby element.Length select element;foreach (string value in lengths) { Console.WriteLine(value); }情況四:Array to List
有點少用。。。就直接用List就好了。。。int[] arr = new int[3]; arr[0] = 2; arr[1] = 3; arr[2] = 5; List<int> list = new List<int>(arr);情況五:Find 功能
List<int> list = new List<int>(new int[] { 19, 23, 29 });// 找大於20int result = list.Find(item => item > 20);Console.WriteLine(result);情況六:Join List to string
List<string> cities = new List<string>(); cities.Add("New York"); cities.Add("Mumbai"); cities.Add("Berlin"); cities.Add("Istanbul"); // Join strings into one CSV line string line = string.Join(",", cities.ToArray()); Console.WriteLine(line);情況七:Insert 功能
List<string> dogs = new List<string>(); // Example List dogs.Add("A dog"); // 內容: A dogs.Add("B dog"); // 內容: A, Bdogs.Insert(1, "C dog"); // 內容: A, C, B情況八: Remove
List<string> animals = new List<string>(); animals.Add("狗"); animals.Add("貓"); animals.Add("魚"); animals.Add("蜘蛛"); animals.Add("螞蟻"); animals.Remove("螞蟻"); // 移除螞蟻,它好像不是動物...animals.RemoveAt(3); // 移除蜘蛛,它好像也不是動物... animals.RemoveRange(0, 2); // 移除0-2...錯殺動物...哈情況九:取得 Dictionary 的 key 值
var dict = new Dictionary<int, bool>(); dict.Add(3, true); dict.Add(5, false); // Get a List of all the Keys List<int> keys = new List<int>(dict.Keys); foreach (int key in keys) { Console.WriteLine(key); }
C#: LINQ to Object 和 LINQ to XML 超好用之一
假設有此一 XML
<?xml version="1.0" encoding="utf-8" ?>
<customers> <customer> <customerid>ALFKI</customerid> <city>Berlin</city> <age>20</age> </customer> <customer> <customerid>BONAP</customerid> <city>Marseille</city> <age>21</age> </customer> <customer> <customerid>CONSH</customerid> <city>London</city> <age>30</age> </customer> <customer> <customerid>EASTC</customerid> <city>London</city> <age>34</age> </customer> <customer> <customerid>FRANS</customerid> <city>Torino</city> <age>35</age> </customer> <customer> <customerid>LONEP</customerid> <city>Portland</city> <age>40</age> </customer> <customer> <customerid>NORTS</customerid> <city>London</city> <age>25</age> </customer> <customer> <customerid>THEBI</customerid> <city>Portland</city> <age>36</age> </customer> </customers> |
還有此一物件
public string CustomerID { get; set; }
public string City { get; set; }
public int Age { get; set; }
public static IEnumerable<Customer> CreateCustomers()
{
return new List<Customer>
{
new Customer { CustomerID = "ALFKI", City = "Berlin", Age=20 },
new Customer { CustomerID = "BONAP", City = "Marseille" , Age=21},
new Customer { CustomerID = "CONSH", City = "London", Age=30 },
new Customer { CustomerID = "EASTC", City = "London", Age=34 },
new Customer { CustomerID = "FRANS", City = "Torino", Age=35 },
new Customer { CustomerID = "LONEP", City = "Portland", Age=40 },
new Customer { CustomerID = "NORTS", City = "London" , Age=25 },
new Customer { CustomerID = "THEBI", City = "Portland", Age=26 }
};
}
}
|
使用方法範例一:把物件理的值拿來做dropdown list
抓取想要的值,可以拿來做dropdown List 來用
public static List<Customer> GetCities()
{
var customers = from customer in Customer.CreateCustomers()
orderby customer.City
select new Customer { City = customer.City
};
return customers.ToList();
}
使用方法範例二:XML來源放到物件裡
我喜歡這方法,我常有一些 需要讀取 web service XML。以前用 XML DOM又慢又沒效率又複雜,又不美觀。。。
public static List<Customer> GetCustomerFromXML(string city)
{
XDocument xmlDoc = XDocument.Load("CustomerXML.xml");
var customers = from customer in xmlDoc.Descendants("customer")
where customer.Element("city").Value == city
select new Customer
{
CustomerID =
customer.Element("customerid").Value,
City =
customer.Element("city").Value,
Age = Convert.ToInt32(customer.Element("age").Value)
};
return customers.ToList();
}
使用方法範例三:從現有List <T>中取出符合條件的<T>
public static List<Customer>
GetCustomersFromObject(string city)
{
var customers = from customer in Customer.CreateCustomers()
where customer.City == city
select new Customer
{
CustomerID =
customer.CustomerID,
City = customer.City,
Age = customer.Age
};
return customers.ToList();
}
位置:
台灣台北市
訂閱:
文章 (Atom)
