For Standard Security: oConn.Open "Driver={Microsoft Access Driver (*.mdb)};" & _ "Dbq=c:\somepath\mydb.mdb;" & _ "Uid=admin;" & _ "Pwd=" If you are using a Workgroup (System database): oConn.Open "Driver={Microsoft Access Driver (*.mdb)};" & _ "Dbq=c:\somepath\mydb.mdb;" & _ "SystemDB=c:\somepath\mydb.mdw;", _ "myUsername", "myPassword" If want to open up the MDB exclusively oConn.Open "Driver={Microsoft Access Driver (*.mdb)};" & _ "Dbq=c:\somepath\mydb.mdb;" & _ "Exclusive=1;" & _ "Uid=admin;" & _ "Pwd=" If MDB is located on a Network Share oConn.Open "Driver={Microsoft Access Driver (*.mdb)};" & _ "Dbq=\\myServer\myShare\myPath\myDb.mdb;" & _ "Uid=admin;" & _ "Pwd=" If MDB is located on a remote machine - Or use an XML Web Service via SOAP Toolkit or ASP.NET - Or upgrade to SQL Server and use an IP connection string - Or use an ADO URL with a remote ASP web page - Or use a MS Remote or RDS connection string If you don't know the path to the MDB (using ASP) <% ' ASP server-side codeoConn.Open "Driver={Microsoft Access Driver (*.mdb)};" & _ "Dbq=" & Server.MapPath(".") & "\myDb.mdb;" & _ "Uid=admin;" & _ "Pwd="%> This assumes the MDB is in the same directory where the ASP page is running. Also make sure this directory has Write permissions for the user account. If you don't know the path to the MDB (using VB) oConn.Open "Driver={Microsoft Access Driver (*.mdb)};" & _ "Dbq=" & App.Path & "\myDb.mdb;" & _ "Uid=admin;" & _ "Pwd=" This assumes the MDB is in the same directory where the application is running. For more information, see: Microsoft Access Driver Programming Considerations To view Microsoft KB articles related to Microsoft Access Driver, click here oConn.Open "Driver={Client Access ODBC Driver (32-bit)};" & _ "System=myAS400;" & _ "Uid=myUsername;" & _ "Pwd=myPassword" For more information, see: A Fast Path to AS/400 Client/Server oConn.Open "Driver={Microsoft dBASE Driver (*.dbf)};" & _ "DriverID=277;" & _ "Dbq=c:\somepath" Then specify the filename in the SQL statement: oRs.Open "Select * From user.dbf", oConn, , ,adCmdText Note: MDAC 2.1 (or greater) requires the Borland Database Engine (BDE) to update dBase DBF files. (Q238431). For more information, see: dBASE Driver Programming Considerations To view Microsoft KB articles related to Microsoft dBASE Driver, click here oConn.Open "Driver={Microsoft Excel Driver (*.xls)};" & _ "DriverId=790;" & _ "Dbq=c:\somepath\mySpreadsheet.xls;" & _ "DefaultDir=c:\somepath" For more information, see: Microsoft Excel Driver Programming Considerations To view Microsoft KB articles related to Microsoft Excel Driver, click here If using INFORMIX 3.30 ODBC Driver oConn.Open "Dsn='';" & _ "Driver={INFORMIX 3.30 32 BIT};" & _ "Host=myHostname;" & _ "Server=myServerName;" & _ "Service=myServiceName;" & _ "Protocol=olsoctcp;" & _ "Database=myDbName;" & _ "UID=myUsername;" & _ "PWD=myPassword" & _' Or oConn.Open "Dsn=myDsn;" & _ "Host=myHostname;" & _ "Server=myServerName;" & _ "Service=myServiceName;" & _ "Protocol=onsoctcp;" & _ "Database=myDbName;" & _ "Uid=myUsername;" & _ "Pwd=myPassword" If using INFORMIX-CLI 2.5 ODBC Driver oConn.Open "Driver={Informix-CLI 2.5 (32 Bit)};" & _ "Server=myServerName;" & _ "Database=myDbName;" & _ "Uid=myUsername;" & _ "Pwd=myPassword" & _ For more information, see: Informix Developer Zone, Connection to ODBC Data Source, For the local machine oConn.Open "Driver={Easysoft IB6 ODBC};" & _ "Server=localhost;" & _ "Database=localhost:C:\Home\Data\Mydb.gdb;" & _ "Uid=myUsername;" & _ "Pwd=myPassword" For a remote machine oConn.Open "Driver={Easysoft IB6 ODBC};" & _ "Server=myMachineName;" & _ "Database=myMachineName:C:\Home\Data\Mydb.gdb;" & _ "Uid=myUsername;" & _ "Pwd=myPassword" For more information, see: Connecting to InterBase and Easysoft For the local machine oConn.Open "Driver={INTERSOLV InterBase ODBC Driver (*.gdb)};" & _ "Server=localhost;" & _ "Database=localhost:C:\Home\Data\Mydb.gdb;" & _ "Uid=myUsername;" & _ "Pwd=myPassword" For a remote machine oConn.Open "Driver={INTERSOLV InterBase ODBC Driver (*.gdb)};" & _ "Server=myMachineName;" & _ "Database=myMachineName:C:\Home\Data\Mydb.gdb;" & _ "Uid=myUsername;" & _ "Pwd=myPassword" For more information, see: Google Search (if you know a direct URL email me) oConn.Open "Driver={Lotus NotesSQL 3.01 (32-bit) ODBC DRIVER (*.nsf)};" & _ "Server=myServerName;" & _ "Database=mydir\myDbName.nsf;" & _ "Uid=myUsername;" & _ "Pwd=myPassword" & _ For more information, see: Connection keywords To connect to a local database oConn.Open "Driver={mySQL};" & _ "Server=MyServerName;" & _ "Option=16834;" & _ "Database=mydb" To connect to a remote database oConn.Open "Driver={mySQL};" & _ "Server=db1.database.com;" & _ "Port=3306;" & _ "Option=131072;" & _ "Stmt=;" & _ "Database=mydb;" & _ "Uid=myUsername;" & _ "Pwd=myPassword" For more information, see: Programs Known to Work with MyODBC For the current Oracle ODBC Driver from Microsoft oConn.Open "Driver={Microsoft ODBC for Oracle};" & _ "Server=OracleServer.world;" & _ "Uid=myUsername;" & _ "Pwd=myPassword" For the older Oracle ODBC Driver from Microsoft oConn.Open "Driver={Microsoft ODBC Driver for Oracle};" & _ "ConnectString=OracleServer.world;" & _ "Uid=myUsername;" & _ "Pwd=myPassword" For more information, see: Connection String Format and Attributes To view Microsoft KB articles related to Microsoft ODBC for Oracle, click here oConn.Open "Driver={Oracle ODBC Driver};" & _ "Dbq=myDBName;" & _ "Uid=myUsername;" & _ "Pwd=myPassword" Where: The DBQ name must be defined in the tnsnames.ora file For more information, see: Oracle8 ODBC Driver Help, Oracle ODBC FAQs, [asporacle] listserv FAQs, and ASPDB Oracle oConn.Open "Driver={Microsoft Paradox Driver (*.db )};" & _ "DriverID=538;" & _ "Fil=Paradox 5.X;" & _ "DefaultDir=c:\dbpath\;" & _ "Dbq=c:\dbpath\;" & _ "CollatingSequence=ASCII" Note: MDAC 2.1 (or greater) requires the Borland Database Engine (BDE) to update Paradox ISAM fDBF files. (Q230126). Note: There is an extra space after "db" in the Paradox Driver name For more information, see: Paradox Driver Programming Considerations To view Microsoft KB articles related to Microsoft Paradox Driver, click here For Standard Security oConn.Open "Driver={SQL Server};" & _ "Server=MyServerName;" & _ "Database=myDatabaseName;" & _ "Uid=myUsername;" & _ "Pwd=myPassword" For Trusted Connection security oConn.Open "Driver={SQL Server};" & _ "Server=MyServerName;" & _ "Database=myDatabaseName;" & _ "Uid=;" & _ "Pwd="' Or oConn.Open "Driver={SQL Server};" & _ "Server=MyServerName;" & _ "Database=myDatabaseName;" & _ "Trusted_Connection=yes" To Prompt user for username and password oConn.Properties("Prompt") = adPromptAlwaysoConn.Open "Driver={SQL Server};" & _ "Server=MyServerName;" & _ "DataBase=myDatabaseName" To connect to SQL Server running on the same computer oConn.Open "Driver={SQL Server};" & _ "Server=(local);" & _ "Database=myDatabaseName;" & _ "Uid=myUsername;" & _ "Pwd=myPassword" To connect to SQL Server running on a remote computer (via an IP address) oConn.Open "Driver={SQL Server};" & _ "Server=xxx.xxx.xxx.xxx;" & _ "Address=xxx.xxx.xxx.xxx,1433;" & _ "Network=DBMSSOCN;" & _ "Database=myDatabaseName;" & _ "Uid=myUsername;" & _ "Pwd=myPassword" Where: - xxx.xxx.xxx.xxx is an IP address - 1433 is the default port number for SQL Server. - "Network=DBMSSOCN" tells ODBC to use TCP/IP rather than Named Pipes (Q238949) For more information, see: SQLDriverConnect (ODBC) To view Microsoft KB articles related to ODBC Driver for SQL Server, click here If using the Sybase System 12 (or 12.5) Enterprise Open Client ODBC Driver oConn.Open "Driver={SYBASE ASE ODBC Driver};" & _ "Srvr=myServerName;" & _ "Uid=myUsername;" & _ "Pwd=myPassword" If using the Sybase System 11 ODBC Driver oConn.Open "Driver={SYBASE SYSTEM 11};" & _ "Srvr=myServerName;" & _ "Uid=myUsername;" & _ "Pwd=myPassword" If using the Intersolv 3.10 Sybase ODBC Driver oConn.Open "Driver={INTERSOLV 3.10 32-BIT Sybase};" & _ "Srvr=myServerName;" & _ "Uid=myUsername;" & _ "Pwd=myPassword" For more information, see: Sybase System 10 ODBC Driver Reference Guide To view Microsoft KB articles related to ODBC Driver for Sybase, click here oConn.Open "ODBC; Driver=Sybase SQL Anywhere 5.0;" & _ "DefaultDir=c:\dbpath\;" & _ "Dbf=c:\sqlany50\mydb.db;" & _ "Uid=myUsername;" & _ "Pwd=myPassword;" & _ "Dsn=""""" Note: Including the DSN tag with a null string is absolutely critical or else you get the dreaded -7778 error. For more information, see: Sybase SQL Anywhere User Guide oConn.Open "Provider=Teradata;" & _ "DBCName=MyDbcName;" & _ "Database=MyDatabaseName;" & _ "Uid=myUsername;" & _ "Pwd=myPassword" For more information, see Teradata ODBC Driver oConn.Open _ "Driver={Microsoft Text Driver (*.txt; *.csv)};" & _ "Dbq=c:\somepath\;" & _ "Extensions=asc,csv,tab,txt" Then specify the filename in the SQL statement: oRs.Open "Select * From customer.csv", _ oConn, adOpenStatic, adLockReadOnly, adCmdText Note: If you are using a Tab delimited file, then make sure you create a schema.ini file, and include the "Format=TabDelimited" option. For more information, see: Text File Driver Programming Considerations To view Microsoft KB articles related to Microsoft Text Driver, click here With a database container oConn.Open "Driver={Microsoft Visual FoxPro Driver};" & _ "SourceType=DBC;" & _ "SourceDB=c:\somepath\mySourceDb.dbc;" & _ "Exclusive=No" Without a database container (Free Table Directory) oConn.Open "Driver={Microsoft Visual FoxPro Driver};" & _ "SourceType=DBF;" & _ "SourceDB=c:\somepath\mySourceDbFolder;" & _ "Exclusive=No" For more information, see: Visual FoxPro ODBC Driver and Q165492 To view Microsoft KB articles related to ODBC Driver for Visual FoxPro, click here |
oConn.Open "Provider=ADSDSOObject;" & _ "User Id=myUsername;" & _ "Password=myPassword" For more information, see: Microsoft OLE DB Provider for Microsoft Active Directory Service To view Microsoft KB articles related to Data Link File, click here oConn.Open "Provider=Advantage OLE DB Provider;" & _ "Data source=c:\myDbfTableDir;" & _ "ServerType=ADS_LOCAL_SERVER;" & _ "TableType=ADS_CDX" For more information, see: Advantage OLE DB Provider (for ADO) oConn.Open "Provider=IBMDA400;" & _ "Data source=myAS400;" & _ "User Id=myUsername;" & _ "Password=myPassword" For more information, see: A Fast Path to AS/400 Client/Server oConn.Open "Provider=SNAOLEDB;" & _ "Data source=myAS400;" & _ "User Id=myUsername;" & _ "Password=myPassword" For more information, see: Connection and ConnectionString Property To view Microsoft KB articles related to OLE DB Provider for AS/400 and VSAM, click here For Data Warehouse oConn.Open "Provider=Commerce.DSO.1;" & _ "Data Source=mscop://InProcConn/Server=mySrvName:" & _ "Catalog=DWSchema:Database=myDBname:" & _ "User=myUsername:Password=myPassword:" & _ "FastLoad=True" ' OroConn.Open "URL=mscop://InProcConn/Server=myServerName:" & _ "Database=myDBname:Catalog=DWSchema:" & _ "User=myUsername:Password=myPassword:" & _ "FastLoad=True" For Profiling System oConn.Open "Provider=Commerce.DSO.1;" & _ "Data Source=mscop://InProcConn/Server=mySrvName:" & _ "Catalog=Profile Definitions:Database=myDBname:" & _ "User=myUsername:Password=myPassword" ' OroConn.Open _ "URL=mscop://InProcConnect/Server=myServerName:" & _ "Database=myDBname:Catalog=Profile Definitions:" & _ "User=myUsername:Password=myPassword" For more information, see: OLE DB Provider for Commerce Server, DataWarehouse, and Profiling System To view Microsoft KB articles related to OLE DB Provider for Commerce Server, click here For TCP/IP connections oConn.Open = "Provider=DB2OLEDB;" & _ "Network Transport Library=TCPIP;" & _ "Network Address=xxx.xxx.xxx.xxx;" & _ "Initial Catalog=MyCatalog;" & _ "Package Collection=MyPackageCollection;" & _ "Default Schema=MySchema;" & _ "User ID=MyUsername;" & _ "Password=MyPassword" For APPC connections oConn.Open = "Provider=DB2OLEDB;" & _ "APPC Local LU Alias=MyLocalLUAlias;" & _ "APPC Remote LU Alias=MyRemoteLUAlias;" & _ "Initial Catalog=MyCatalog;" & _ "Package Collection=MyPackageCollection;" & _ "Default Schema=MySchema;" & _ "User ID=MyUsername;" & _ "Password=MyPassword" For more information, see: Connection, ConnectionString Property, and Q218590 To view Microsoft KB articles related to OLE DB Provider for DB2, click here The Microsoft OLE DB Provider for DTS Packages is a read-only provider that exposes Data Transformation Services Package Data Source Objects. oConn.Open = "Provider=DTSPackageDSO;" & _ "Data Source=mydatasource" For more information, see: OLE DB Providers Tested with SQL Server To view Microsoft KB articles related to OLE DB Provider for DTS Packages, click here oConn.Provider = "EXOLEDB.DataSource"oConn.Open = "http://myServerName/myVirtualRootName" For more information, see: Exchange OLE DB Provider, Messaging, Calendaring, Contacts, and Exchange using ADO objects To view Microsoft KB articles related to OLE DB Provider for Exchange, click here Actually there is no OLE DB Provider for Excel. However, you can use the OLE DB Provider for JET to read and write data in Microsoft Excel workbooks. Or you can use the ODBC Driver for Excel. oConn.Open "Provider=MSIDXS;" & _ "Data source=MyCatalog" For more information, see: Microsoft OLE DB Provider for Microsoft Indexing Service To view Microsoft KB articles related to OLE DB Provider for Index Server, click here oConn.Open "Provider=MSDAIPP.DSO;" & _ "Data Source=http://mywebsite/myDir;" & _ "User Id=myUsername;" & _ "Password=myPassword" ' Or oConn.Open "URL=http://mywebsite/myDir;" & _ "User Id=myUsername;" & _ "Password=myPassword" For more information, see: Microsoft OLE DB Provider for Internet Publishing and Q245359 To view Microsoft KB articles related to OLE DB Provider for Internet Publishing, click here For standard security oConn.Open "Provider=Microsoft.Jet.OLEDB.4.0;" & _ "Data Source=c:\somepath\myDb.mdb;" & _ "User Id=admin;" & _ "Password=" If using a Workgroup (System Database) oConn.Open "Provider=Microsoft.Jet.OLEDB.4.0;" & _ "Data Source=c:\somepath\mydb.mdb;" & _ "Jet OLEDB:System Database=MySystem.mdw", _ "myUsername", "myPassword" Note, remember to convert both the MDB and the MDW to the 4.0 database format when using the 4.0 OLE DB Provider. If MDB has a database password oConn.Open "Provider=Microsoft.Jet.OLEDB.4.0;" & _ "Data Source=c:\somepath\mydb.mdb;" & _ "Jet OLEDB:Database Password=MyDbPassword", _ "myUsername", "myPassword" If want to open up the MDB exclusively oConn.Mode = adModeShareExclusiveoConn.Open "Provider=Microsoft.Jet.OLEDB.4.0;" & _ "Data Source=c:\somepath\myDb.mdb;" & _ "User Id=admin;" & _ "Password=" If MDB is located on a network share oConn.Open "Provider=Microsoft.Jet.OLEDB.4.0;" & _ "Data Source=\\myServer\myShare\myPath\myDb.mdb" If MDB is located on a remote machine - Or use an XML Web Service via
happy4u
2005. 6. 21. 15:55
2005. 6. 21. 15:55
.NET Tools Ten Must-Have Tools Every Developer Should Download NowNUnit to write unit tests -> 너무나도 유명한 Unit Testing framework (CSUnit이 사용하기는 더 편한듯...) NDoc to create code documentation -> 내 블로그에 예전에 소개한 util, 뽀다구나는 문서 제작할 때 좋죠~ NAnt to build your solutions CodeSmith to generate code FxCop to police your code -> 코드 분석 툴이라는데... 아직 사용해 보진 않아서... 어떨런지.. Snippet Compiler to compile small bits of code -> 작게 테스트 코드를 만들고 실행해 보고 할 때 사용하는 툴 -> 정말 좋은 거라 생각했는데.. 오늘 함 써 보니... --'' 자동 완성에 길들여진 나를 전혀 충족시켜주지 못하네요 ㅋㅋ 비추 Two different switcher tools, the ASP.NET Version Switcher and the Visual Studio .NET Project Converter Regulator to build regular expressions -> 정규식 만들 때 사용하면 유용한 툴 (개인적으로 자주 참고 하는 Regexlib.com 과 연관된 툴이네요) .NET Reflector to examine assemblies 위 열개인데.. 써 본거라곤 세개 정도 밖에는 없네요 --'' 개인 적으로 맘에 드는 툴 SnippetCompiler : 테스트 코드 만들려고 매번 빈 프로젝트를 만들곤 했는데..
..more
>접기 This article discusses: - NUnit to write unit tests
- NDoc to create code documentation
- NAnt to build your solutions
- CodeSmith to generate code
- FxCop to police your code
- Snippet Compiler to compile small bits of code
- Two different switcher tools, the ASP.NET Version Switcher and the Visual Studio .NET Project Converter
- Regulator to build regular expressions
- .NET Reflector to examine assemblies
| This article uses the following technologies: .NET, C# or Visual Basic .NET, Visual Studio .NET
|
ou cannot expect to build a first-class application unless you use the best available tools. Besides well-known tools such as Visual Studio® .NET, there are a multitude of small, lesser-known tools available from the .NET community. In this article, I'm going to introduce you to some of the best free tools available today that target .NET development. I'll walk you through a quick tutorial of how to use each of them, some of which will save you a minute here and there, while others may completely change the way that you write code. Because I am squeezing so many different tools into this single article, I will not be able to cover each of them extensively, but you should learn enough about each to decide which tools are useful for your projects. Snippet CompilerThe Snippet Compiler is a small Windows®-based application that allows you to write, compile, and run code. This tool is useful if you have small pieces of code for which you don't want to create an entire Visual Studio .NET project (along with all the files that come with it). As an example, let's say that I wanted to show you how to launch another application from the Microsoft® .NET Framework. In the Snippet Compiler I would start by creating a new file which creates a small console application. The snippet can be created inside the Main method of the console application, which is what I will do here. The following code snippet demonstrates how to create an instance of Notepad from the .NET Framework: System.Diagnostics.Process proc = new System.Diagnostics.Process(); proc.StartInfo.FileName= "notepad.exe"; proc.Start(); proc.WaitForExit(); Of course this snippet would not compile by itself, but that is where Snippet Compiler comes into play. Figure 1 shows this code sample in Snippet Compiler. Figure 1 Snippet CompilerTo test this snippet, just press the play button (green triangle), and it will run in debug mode. The snippet will generate a console application popup, and Notepad will appear. When you close Notepad, the console application will close as well. Personally, I have found Snippet Compiler to be invaluable when trying to create a small example for someone who has asked me for help, when normally I would have to create a project, make sure everything compiles, send them the code snippet, and then delete the project. Snippet Compiler makes this process much easier and much more pleasant. Snippet Compiler was written by Jeff Key and can be downloaded from http://www.sliver.com/dotnet/SnippetCompiler. RegulatorRegulator is the most recent addition to my top tools list. It is a full-featured tool that makes it easy to build and test regular expressions. There is a renewed interest in regular expressions because of the excellent support for them in the .NET Framework. Regular expressions are used to define patterns in strings based on characters, frequency, and character order. They are most commonly used as a means to validate user input or as a way to find a string of characters inside a larger string—for instance, when looking for a URL or e-mail address on a Web page. Regulator allows you to enter a regular expression and some input against which you would be running this expression. This way you can see how the regular expression will act and what kind of matches it will return before implementing it in your application. Figure 2 shows Regulator with a simple regular expression. The document contains the regular expression, in this example it is [0-9]* which should match any number of digits in a row. The box in the bottom-right contains the input for this regular expression, and the box on the bottom-left shows the matches that this regular expression finds in the input. The ability to write and test regular expressions in a separate application like this is much easier than trying to work with them in your app. One of the best features in Regulator is the ability to search the online regular expressions library at regexlib.com. For example, if you enter the string "phone" in the search box, you will find more than 20 different regular expressions that will match various phone numbers, including expressions for UK, Australian, and many other phone numbers. Regulator was written by Roy Osherove and can be downloaded at http://regex.osherove.com. CodeSmithCodeSmith is a template-based code-generation tool that uses a syntax similar to ASP.NET to generate any type of code or text. Unlike many other code-generation tools, CodeSmith does not require you to subscribe to a particular application design or architecture. Using CodeSmith, you can generate anything from a simple, strongly typed collection to an entire application. When you are building an application, you will often find yourself repeating certain tasks, whether it's writing data access code or building custom collections. CodeSmith is particularly useful at such times because you can write templates to automate those tasks and not only improve your productivity but also automate the tasks that are the most tedious to perform. CodeSmith ships with a number of templates, including ones for all the .NET collection types as well as ones to generate stored procedures, but the real power of this tool comes from being able to create custom templates. To get you started, I'll provide a quick introduction to building a custom template. Building a Custom TemplateCodeSmith templates are simply text files which you can create in any text editor. Their only requirement is that they be saved with the .cst file extension. The sample template that I'm going to build will accept a string and then build a class based on that string. The first step to creating a template is to add the template header, which declares the language of the template, the target language, and a brief description of the template: <%@ CodeTemplate Language="C#" TargetLanguage="C#" Description="Car Template" %> The next part of the template is the property declarations, where you declare the properties that will be specified each time the template is run. With this template, the single property that I'm going to use is just a string, so the property declaration looks like this: <%@ Property Name="ClassName" Type="String" Category="Context" Description="Class Name" %> This property declaration will make the ClassName property appear in the CodeSmith property window so that it can be specified when the template is run. The next step is to actually build the body of the template, which is very similar to coding with ASP.NET. You can see the body of the template in Figure 3. [Editor's Update - 6/16/2004: The code in Figure 3 has been updated to be safe for multithreaded operations.] As you can see, the template will take the string input and generate a singleton class using that class name. In the template body, the same opening and closing tags are used as in ASP.NET. In this template, I am simply inserting the property value, but you can also use any type of .NET code inside these tags. Once the template is complete, you load it into CodeSmith by either double-clicking or opening it from the CodeSmith application. Figure 4 shows this template loaded into CodeSmith. You can see that the property on the left is the one I declared in the template. If I enter "SingletonClass" as the class name and click the Generate button, the class shown in the bottom part of Figure 3 will be generated. CodeSmith is relatively easy to use and can produce some incredible results if applied correctly. One of the most common sections of an application that is targeted for code generation is the data access layer. CodeSmith includes a special assembly called the SchemaExplorer which can be used to generate templates from tables, stored procedures, or almost any other SQL Server™ object. CodeSmith was written by Eric J. Smith and is available for download at http://www.ericjsmith.net/codesmith. NUnitNUnit is an open source unit testing framework built for the .NET Framework. NUnit allows you to write tests in the language of your choice to test a specific function of your application. Unit tests are an excellent way to test the functionality of your code when you first write it, and also to provide a method for regression testing of your application. The NUnit application provides a framework for writing unit tests, as well as a graphical interface to run these tests and view the results. Writing an NUnit TestAs an example, I'm going to test the functionality of the Hashtable class in the .NET Framework to determine if two objects can be added and then retrieved. My first step will be to add a reference to the NUnit.Framework assembly, which will give me access to the attributes and methods of the NUnit framework. Next I'll create a class and mark it with the TestFixture attribute. This attribute lets NUnit know that this class contains NUnit tests: using System; using System.Collections; using NUnit.Framework; namespace NUnitExample { [TestFixture] public class HashtableTest { public HashtableTest() { } } } Next I'll create a method and mark it with the [Test] attribute so that NUnit knows that this method is a test. Then I'll set up a Hashtable and add two values to it, then use the Assert.AreEqual method to see if I can retrieve the same values that I added to the Hashtable, as shown in the following: [Test] public void HashtableAddTest() { Hashtable ht = new Hashtable(); ht.Add("Key1", "Value1"); ht.Add("Key2", "Value2"); Assert.AreEqual("Value1", ht["Key1"], "Wrong object returned!"); Assert.AreEqual("Value2", ht["Key2"], "Wrong object returned!"); } This will confirm that I can add and then retrieve values from the Hashtable—a simple test, but one that showcases the capabilities of NUnit. There are a number of test types, as well as various Assert methods, that can be used to test every part of your code. To run this test, I'll need to build the project, open the generated assembly in the NUnit application, and then click the Run button. Figure 5 shows the results. I get a warm and fuzzy feeling when I see that big green bar because it lets me know that the test passed. This simple example shows how easy and powerful NUnit and unit testing can be. Being able to write a unit test that can be saved and rerun whenever you change code not only makes it easier for you to detect defects in your code, but the result is that you can deliver better applications. Figure 5 NUnitNUnit is an open-source project that is available for download from http://www.nunit.org. There is also an excellent NUnit Visual Studio .NET add-in which allows you to run unit tests directly from Visual Studio. This can be found at http://sourceforge.net/projects/nunitaddin. For more information on NUnit and its place in test-driven development, see the article "Test-Driven C#: Improve the Design and Flexibility of Your Project with Extreme Programming Techniques" in the April 2004 issue of MSDN® Magazine. FxCopThe .NET Framework is very powerful, which means there is great potential to create excellent applications, but there is equal opportunity to create poor programs. FxCop is one of the tools that can be used to help create better applications by enabling you to examine an assembly and check it for compliance using a number of different rules. FxCop comes with a set number of rules created by Microsoft, but you can also create and include your own rules. For instance, if you decided that all classes should have a default constructor that takes no arguments, you could write a rule that checks for a constructor on each class of an assembly. This way, no matter who writes the code, you will have a certain level of consistency. If you want more information on creating custom rules, see John Robbins' Bugslayer column on the subject in the June 2004 issue of MSDN Magazine. So let's take a look at FxCop in action and see what it finds wrong with the NUnitExample assembly that I have been working with. When you open FxCop you first need to create an FxCop project and then add to it the assembly that you want to test. Once the assembly is added to the project, you can press Analyze, and FxCop will examine the assembly. The errors and warning found in this assembly are shown in Figure 6. FxCop found a couple of problems with my assembly. You can double-click on an error to see the details, including a description of the rule and where you can find more information. (Something you can do for fun is run FxCop on the Framework assemblies and see what turns up.) FxCop can help you create better, more consistent code, but it cannot make up for poor application design or just plain poor programming. FxCop is also not a replacement for peer code review, but because it can catch a lot of errors before code review, more time can be spent on serious issues rather than having to worry about naming conventions. FxCop was developed by Microsoft and is available for download from http://www.gotdotnet.com/team/fxcop. Lutz Roeder's .NET ReflectorThe next essential tool is called .NET Reflector, which is a class browser and decompiler that can examine an assembly and show you just about all of its secrets. The .NET Framework introduced reflection which can be used to examine any .NET-based code, whether it is a single class or an entire assembly. Reflection can also be used to retrieve information about the various classes, methods, and properties included in a particular assembly. Using .NET Reflector, you can browse the classes and methods of an assembly, you can examine the Microsoft intermediate language (MSIL) generated by these classes and methods, and you can decompile the classes and methods and see the equivalent in C# or Visual Basic® .NET. To demonstrate the workings of .NET Reflector, I am going to load and examine the NUnitExample assembly already shown. Figure 7 shows this assembly loaded in .NET Reflector. Figure 7 NUnitExample AssemblyInside of .NET Reflector there are various tools that you can use to examine this assembly further. To view the MSIL that makes up a method, click on the method and select Disassembler from the menu. In addition to being able to view the MSIL, you can also view the method as C# by selecting Decompiler under the Tools menu. You could also view this method decompiled to Visual Basic .NET or Delphi by changing your selection under the Languages menu. Here is the code that .NET Reflector generated: public void HashtableAddTest() { Hashtable hashtable1; hashtable1 = new Hashtable(); hashtable1.Add("Key1", "Value1"); hashtable1.Add("Key2", "Value2"); Assert.AreEqual("Value1", hashtable1["Key1"], "Wrong object returned!"); Assert.AreEqual("Value2", hashtable1["Key2"], "Wrong object returned!"); } The previous code looks very much like the code I actually wrote for this method. Here is the actual code from this assembly: public void HashtableAddTest() { Hashtable ht = new Hashtable(); ht.Add("Key1", "Value1"); ht.Add("Key2", "Value2"); Assert.AreEqual("Value1", ht["Key1"], "Wrong object returned!"); Assert.AreEqual("Value2", ht["Key2"], "Wrong object returned!"); } Although there are some minor differences with the code, they are functionally identical. While this example was a good way to show actual code versus decompiled code, it does not represent what I consider to be the best use of .NET Reflector, which is to examine .NET Framework assemblies and methods. The .NET Framework offers many different ways to perform similar operations. For example, if you need to read a set of data from XML, there are a variety of different ways to do this using XmlDocument, XPathNavigator, or XmlReader. By using .NET Reflector, you can see what Microsoft used when writing the ReadXml method of the DataSet, or what they did when reading data from the configuration files. .NET Reflector is also an excellent way to see the best practices for creating objects like HttpHandlers or configuration handlers because you get to see how the team at Microsoft actually built those objects in the Framework. .NET Reflector was written by Lutz Roeder and can be downloaded from http://www.aisto.com/roeder/dotnet. NDocCode documentation is almost always a dreaded task. I am not talking about the early design documents, or even the more detailed design documents; I am talking about documenting individual methods and properties on classes. The NDoc tool will automatically generate documentation for your code using reflection to examine the assembly and using the XML generated from your C# XML comments. XML comments are only available for C#, but there is a Visual Studio .NET Power Toy called VBCommenter which will do something similar for Visual Basic .NET. In addition, the next release of Visual Studio will support XML comments for more languages. With NDoc you are technically still documenting your code, but you are documenting as you write it (in the XML comments), which is much easier to swallow. The first step when using NDoc is to turn on XML comments generation for your assembly. Right-click the project and select Properties | Configuration Properties | Build, then enter a path in which to save the XML file in the XML Documentation File option. When the project is built, an XML file will be created with all of the XML comments included. Here is a look at a method from the NUnit example documented with XML: /// <summary> /// This test adds a number of values to the Hashtable collection /// and then retrieves those values and checks if they match. /// </summary> [Test] public void HashtableAddTest() { //Method Body Here } The XML documentation on this method will be extracted and saved in the XML file, shown here: <member name="M:NUnitExample.HashtableTest.HashtableAddTest"> <summary>This test adds a number of values to the Hashtable collection and then retrieves those values and checks if they match.</summary> </member> NDoc uses reflection to look at your assembly, then reads the XML in this document, and matches them up. NDoc uses this data to create any number of different documentation formats, including HTML help files (CHMs). After generating the XML file, the next step is to load the assembly and the XML file into NDoc so they can be processed. This is done simply by opening NDoc and clicking the Add button. Once the assembly and XML file are loaded into NDoc and after you customize the output using the range of properties available, clicking on the Generate button will start the process of generating the documentation. Using the default properties, NDoc generates some very attractive and functional .html and .chm files, thereby automating in a quick and efficient manner what would otherwise be a tedious task. NDoc is an open source project and can be downloaded from http://ndoc.sourceforge.net. NAntNAnt is a .NET-based build tool that, unlike the current version of Visual Studio .NET, makes it easy to create a build process for your project. When you have a large number of developers working on a single project, you can't rely on the build from a single user's box. You also do not want to have to build the project manually on a regular basis. Instead, you create an automated build process that runs every night. NAnt allows you to build your solution, copy files, run NUnit tests, send e-mail, and much more. Unfortunately, NAnt is lacking a nice looking graphical interface, but it does have a console application and XML files that specify which tasks should be completed during the build process. Note that MSBuild, the new build platform that's part of Visual Studio 2005, provides for very robust build scenarios and is similarly driven by XML-based project files. NAnt in ActionIn this example I am going to create an NAnt build file for the NUnitExample solution that I created earlier. First I need to create an XML file with the .build extension, place it in the root of my project, and then add an XML declaration to the top of the file. The first tag I need to add to the file is the project tag: <?xml version="1.0"?> <project name="NUnit Example" default="build" basedir="."> <description>The NUnit Example Project</description> </project> The project tag is also used to set the name of the project, the default target, and the base directory. The description tag is used to set a brief description of this project. Next, I'll add the property tag, which can be used to store a setting in a single location that can then be accessed from anywhere in the file. In this case, I am going to create a property called debug, which I can then set to true or false, reflecting whether or not I want the project to be compiled in the debug configuration. (In the end, this particular property does not actually affect how the project will be built; it is simply a variable that you set and which will be read from later when you are actually determining how to build the project.) Next, I need to create a target tag. A project can contain multiple targets which can be specified when NAnt is run. If no target is specified, the default is used, which I set in the project element. In this example, the default target is build. Let's take a look at the target element, which will contain the majority of the build info: <target name="build" description="compiles the source code"> </target> Inside the target element, I am going to set the name of the target to build and create a description of what this target will do. I'll also create a csc element, which is used to specify what should be passed to the csc C# compiler. Let's take a look at the csc element: <csc target="library" output=".\bin\debug\NUnitExample.dll" debug="${debug}"> <references> <includes name="C:\program files\NUnit V2.1\bin\NUnit.Framework.dll"/> </references> <sources> <includes name="HashtableTest.cs"/> </sources> </csc> First, I have to set the target of the csc element. In this case I will be creating a .dll file so I set the target to library. Next, I have to set the output of the csc element, which is where the .dll file will be created. Finally, I need to set the debug property, which determines whether the project will be compiled in debug. Since I created a property earlier to store this value, I can use the following string to access the value of that property: ${debug}. The csc element also contains a number of sub-elements. I need to create two elements: the references element will tell NAnt which assemblies I need to reference for this project, and the sources element will tell NAnt which files to include in the build. In this example, I reference the NUnit.Framework.dll assembly and include the HashtableTest.cs file. The complete build file is shown in Figure 8. (You would normally also create a clean target that would be used to delete the generated files, but I have omitted it for the sake of brevity.) To build this file I need to go to the root directory of my project, where the build file is located, and execute nant.exe from that location. If the build is successful, you can find the .dll and .pdb file in the bin directory of this application. While using NAnt is definitely not as easy as clicking Build in Visual Studio, it is a very powerful tool for developing a build process that runs on an automated schedule. NAnt also includes helpful features such as the ability to run unit tests or copy additional files (features that are not supported by the current Visual Studio build process). NAnt is an open source project and can be downloaded from http://sourceforge.net/projects/nant. Switch ToolsI have lumped together two separate tools under the heading Switch Tools. These two tools are rather simple, but can be extremely useful. The first is the ASP.NET Version Switcher, which can be used to switch the version of ASP.NET that a virtual directory is running under. The second tool is the Visual Studio Converter, which can be used to switch a project file from Visual Studio .NET 2002 to Visual Studio .NET 2003. When IIS handles a request, it looks at the extension of the file that is being requested, and then based on the extension mappings for that Web site or virtual directory, it either delegates the request to an ISAPI extension or handles it itself. This is how ASP.NET works; extension mappings are registered for all of the ASP.NET extensions and directs them to the aspnet_isapi.dll. This works flawlessly until you install ASP.NET 1.1, which upgrades the extension mapping to the new version of aspnet_isapi.dll. This causes errors when an application built on ASP.NET 1.0 tries to run with version 1.1. To fix this, you can switch all of the extension mappings back to the 1.0 version of aspnet_isapi.dll, but with 18 extension mappings it is not a lot of fun to do this by hand. This is where the ASP.NET Version Switcher becomes useful. This small utility can be used to switch the version of the .NET Framework that any single ASP.NET application is using. Figure 9 ASP.NET Version SwitcherFigure 9 shows the ASP.NET Version Switcher in action. Using it is as simple as selecting the application and then selecting the version of the .NET Framework that you would like the application to use. The tool then uses the aspnet_regiis.exe command-line tool to switch the application to the selected version of the Framework. This tool will become even more useful as future versions of ASP.NET and the .NET Framework are released. ASP.NET Version Switcher was written by Denis Bauer and is available for download from http://www.denisbauer.com/NETTools/ASPNETVersionSwitcher.aspx. The Visual Studio .NET Project Converter (see Figure 10) is very similar to the ASP.NET Version Switcher, except that it is used to switch the version of a Visual Studio project file. Even though there is only a small difference between versions 1.0 and 1.1 of the .NET Framework, once a project file from Visual Studio .NET 2002 is converted to Visual Studio .NET 2003, it cannot be converted back. While this might not be an issue most of the time (since there are few breaking changes between the .NET Framework versions 1.0 and 1.1), at some point you may need to switch a project back. This converter can convert any solution or project file from Visual Studio 7.1 (Visual Studio .NET 2003) to Visual Studio 7.0 (Visual Studio .NET 2002), and back if necessary. Figure 10 Visual Studio .NET Project ConverterThe Visual Studio .NET Project Converter was written by Dacris Software. It is available for download from http://www.codeproject.com/macro/vsconvert.asp. ConclusionThis has been a bit of a whirlwind tour of these tools, but I have tried to present you with at least enough information to whet your appetite. I trust that this article has provided you with some insight into a couple of free tools that you can start using right away to write better projects. I also urge you to make sure you have all the other right tools available to you, whether it is newest version of Visual Studio, a powerful computer, or a free utility. Having the right tools can make all the difference. James Avery is a consultant working with .NET and other Microsoft technologies. He has written a number of books and articles, his most recent book being ASP.NET Setup and Configuration Pocket Reference (Microsoft Press, 2003). You can e-mail him at javery@infozerk.com and read his weblog at http://www.dotavery.com/blog.
From the July 2004 issue of MSDN Magazine. Get it at your local newsstand, or better yet, subscribe. 출처 : http://msdn.microsoft.com/msdnmag/issues/04/07/MustHaveTools/default.aspx
happy4u
2005. 5. 31. 15:03
2005. 5. 31. 15:03
OUTPUT parameter에 null값이 담겨져 온 경우 C#에서 비교하는 방법 paramNull.IsNullable = true; <-- 이 부분은 없어도 비교 하는데는 문제가 없습니다. if(paramNull.Value == DBNull.Value) { .... } 그냥 null로 되는 줄 알았는데, 안되고 DBNull이라는 객체를 이용해야 한다. isNullable이라는 속성은 null값을 허용하겠느냐를 결정하는 건데, default가 false이다.
happy4u
2005. 5. 16. 18:23
2005. 5. 16. 18:23
happy4u
2005. 4. 24. 10:27
2005. 4. 24. 10:27
요즘 C#프로그래밍을 하면서 조금씩 조금씩 OOP를 익히고 있다. OOP를 하기 전에 들었던 몇가지 지식들을 외의 여러가지 OOP의 rule들에 대해 궁금했었는데, 총정리해놓은 문서를 찾아서 스크립 해 왔다. 원본은 검정글씨, 덧붙인 내용은 빨간 글씨로 구분했습니다. 한글로 덧붙인 설명은 마이크로 소프트웨어를 참고했습니다. 2005년 1월호 ~ 4월호
..more
>접기 IntroductionOO Design is more than just using an OO language. Over the years many bright programmers have built up a collection of rules that help to build well designed maintainable code. This article lists the main rules of OO programming. The intention is to inspire the reader to think about these rules and make further reading. There is a lot of material on the web that drills down into more details with plenty of examples. Ivar Jacabson said ”All systems change during their life cycles. This must be borne in mind when developing systems expected to last longer than the first version”. In other words software requirements change with time. The goal of Object Orientated Design is to program in such a way that such changes to the software are predictable and do not make a large impact in the program. In other words it should be stable in the presence of change Bad design is characterized by - A single change affects many other parts of the system (Rigidity)
- A single change affects unexpected parts of the system (Fragility)
- It is hard to reuse in another application (Immobility)
The Dependency Inversion Principle DIP한글로는 '의존 관계 역전 원칙' Imagine you have a simple database program. You don’t want to change the entire application when changing the database. This principle is targeted at removing such unwanted interdependency that can cause a design to be fragile. The rule states - High level modules should not depend upon low level modules. Both should depend upon abstractions
- Abstractions should not depend upon details. Details should depend upon abstractions
Booch said “All well structured object orientated architectures have clearly-defined layers with each layer providing some coherent set of services through a well defined and controlled interface.” In other words design applications in layers where high level layers call lower level layers using Abstract interfaces. To conform to the principle of dependency inversion, we must isolate abstraction from the details of the problem. Then we must direct the dependencies of the design upon the abstractions. Good dependencies are extremely unlikely to change. In other words they are stable. We would like to base our architectural design around stable, non-volatile modules. -> 마이크로소프트웨어 2005년 5월호 p202 '객체지향 소프트웨어 설계의 원칙들 5' 참고 The Open-Close Principle OCP한글로는 '개방-패쇄 원칙' Software entities (Classes, Modules, functions etc) should be open for extension, but closed for modification In other words design classes that never change. When a new requirements come add new code and don’t edit existing code. It is not possible to close against all possible changes. Therefore an experienced developer needs to understand the possible future wishes of users in order to make Strategic Closure. There are two ways of closure: - Using Abstraction to gain explicit closure - This means the programmer applies abstraction to those parts of the programmer the designer feels are subject to change.
- Using Data Driven Approach to achieve closure
-> 마이크로소프트웨어 2005년 1월호 p202 '객체지향 소프트웨어 설계의 원칙들 1' 참고 -> 마이크로소프트웨어 2005년 5월호 p204 '객체지향 소프트웨어 설계의 원칙들 5' 참고 Liskov Substitution Principle LSP 한글로는 '리스코프 교체 원칙' Every function that operates upon a reference or pointer to a base class should be able to operate on derivatives of that base class without knowing it. This means that virtual member functions of the derived class must expect only all the corresponding member functions of the base class. In other words any function that uses a base class must not be confused when a derived class is substituted for the base class This is a difficult principle to apply. To conform avoid overwriting base class functions because this involves programming with details, instead try to program in abstractions If this is violated then functions that operate on the pointers must first check the type of the actual object in order to work correctly. -> 마이크로소프트웨어 2005년 5월호 p203 '객체지향 소프트웨어 설계의 원칙들 5' 참고 Heuristics and ConventionsMake all member variables Private: Otherwise no function that calls the class can be closed to change. For example a status variable can change from Boolean to an enumeration, if this is not handled as a property then we cannot close status. This is called encapsulation. No Global Variables. Because misbehaving modules may write erroneous data to such global variables whose effect can be felt in many places throughout the program. Sometimes Global variables are useful e.g. cout and cin in c++. If they do not violate the open close principle then sometimes they are worth the style violation Stability Dependencies Principle SDPThe dependencies between packages in a design should be in the direction of stability of the packages. A package should only depend upon packages that are more stable than it is. Some volatility is necessary if the design is to be maintained. This is achieved by using the Common Closure Principle, in this way we design packages to be volatile and we expect them to change. Any package that we expect to be volatile should not be depended upon by a package that is difficult to change. Some things we don’t want to change. For example architectural decisions should be stable and not at all volatile. Therefore classes that encapsulate the high level design should be stable. The stable Abstractions Principle SAPPackages that are maximally stable should be maximally abstract. Instable packages should be concrete. The abstraction of a package should be in proportion to it's stability Common Reuse Principle CRPIf you reuse one class of a package, you reuse them all. This because any package delivered contains a released set of classes, therefore a change in any class means a new release of the entire package. The Reuse / Release Equivalence Principle REPThe granule of reuse is the granule of release. Only components that are released through a tracking system can be effectively reused. This principle is important when there are several teams working on an application. To avoid one team disrupting another all packages used are tested and released. In this way the introduction of modified packages is in a controlled way. The Common Closure Principle CCPThe classes in a package should be closed together against the same kinds of changes. Any change in a package affects all classes in the package. Just like a well organized team has a common goal because they all have to work together. This principle means that you should have a common strategic closure concept used through all classes in a package because they have to be released all together. The stability Dependencies Principle SDPThe dependencies between packages in a design should be in the direction of stability of the packages. A package should only depend upon packages that are more stable than it is. Designs that are highly interdependent tend to be rigid, not reusable and hard to maintain The Acyclic Dependencies Principle (ADP) The dependency structure between package must be a Direct Acyclic Graph (DAG). This means that if you plot out all packages it should be possible to arrange the dependencies to always point from top to bottom. Also it should not be possible to follow any lines of dependence and end up back at the same package. Because such packages would have to be released all at the same time defeating the object of having them as separate packages The Interface Segregation Principle ISP한글로는 '인터페이스 격리 원칙' Clients should not be forced to depend upon interfaces that they don’t use. This principle deals with the disadvantages of fat interfaces. Fat interfaces are not cohesive. In other words the interfaces of classes should be broken into groups of member functions. Each groups servers a different set of clients. Separation can be achieved by: - Separation through Delegation
- Separation through multiple inheritance
If this principle is violated then there is a coupling between all clients -> 마이크로소프트웨어 2005년 3월호 p161 '객체지향 소프트웨어 설계의 원칙들 3' 참고 -> 마이크로소프트웨어 2005년 5월호 p203 '객체지향 소프트웨어 설계의 원칙들 5' 참고 Polyad vs MonadMonad is when properties are grouped into 1 single object that is then passed in a function parameter. Unfortunately this brings a dependency across all properties in that single object. Therefore its better to pass smaller objects (Polyad), in this way the dependencies are broken into smaller groups. Interface PollutionAs we build up classes there is a tendency for us to add functionality that is specific for a particular implementation. In this way the interface gets populated by functions and properties that are not required if the class was in a different context, thus making the interface fat. In this way this violates the Liskov Substitution principle. Separate Clients means separate interfaces There is a backward force applied by clients upon interfaces. For example a user may wish to add a trivial extra function that cannot be exactly positioned in existing interfaces. Single Responsibility Principle : SRP 하나의 클래스는 하나의 책임만을 가져야 한다. -> 마이크로소프트웨어 2005년 2월호 p155 '객체지향 소프트웨어 설계의 원칙들 2' 참고 -> 마이크로소프트웨어 2005년 5월호 p201 '객체지향 소프트웨어 설계의 원칙들 5' 참고 About Nigel-Findlater
| I am a VB.NET Software Architect currently working in a medical company. My primary interests are Windows Applications, Pocket PC and ASP.NET. I have spent the last 15 years programming, and managing Software Projects. Click here to view Nigel-Findlater's online profile. |
출처 : http://www.codeproject.com/gen/design/nfOORules.asp
happy4u
2005. 4. 19. 13:40
2005. 4. 19. 13:40
c#으로 자료구조 공부하시는 분들께 좋은 자료가 될 것 같네요. Data Structures and Algorithms with Object-Oriented Design Patterns in C#Bruno R. Preiss B.A.Sc., M.A.Sc., Ph.D., P.Eng.
출처 : http://www.brpreiss.com/books/opus6/html/book.html
happy4u
2005. 4. 6. 14:49
2005. 4. 6. 14:49
웹서비스를 만들어 배포 하려고 하다가 방법을 찾던 중 발견한 내용. 배포방법에는 1. 수동 2. 프로젝트 복사 기능 3. 웹 설치 프로젝트를 이용하는 방법 이 있다고 한다. 2번 방법이 나온 곳을 알고 계신분 덧글 부탁..
..more
>접기 1. 수동 일단, 복사할 파일은 .asmx와 /bin/***.dll 파일입니다. 이외에 global.asax와 Web.config 파일을 사용한다면, 이 파일도 함께 복사하여야 합니다. 운영 웹 서버에 디렉토리를 만든 뒤에, 앞서 언급한 파일을 복사하신 후에, IIS 콘솔에서 가상디렉토리를 만드시면 됩니다. 출처 : http://www.devpia.com/Forum/BoardView.aspx?no=24222&page=6&Tpage=11&forumname=aspnet_qa&stype=&ctType=&KeyR=title&KeyC= 3. 웹 설치 프로젝트 이용 IntroductionDeployment is a great feature in Visual Studio .NET which allows you to deploy your applications by creating a Setup Program. You can make a setup project for both your Windows and Web applications. Using this feature for deploying has many advantages for example: - Installed applications can be uninstalled completely.
- If an error occurred through installation process, the system goes back to the state of before the installation.
- Adding user interface to setup project easily.
- Making setup project on different kinds of distribution media such as CD or floppy disks.
- Easy reinstallation when installed files get corrupted.
In this article, I will create a simple ASP.NET Web project and then create a setup project for deploying that. First of all create an ASP.NET Web project using Visual Studio .NET and name it for example "TestWeb". In the WebForm designer (WebForm1.aspx). Drag and drop a Label and a button server control. Double click on button and then add the following code and compile the project. private void Button1_Click(object sender, System.EventArgs e) { Label1.Text = "My first deployment web project"; } Creating the Web Setup projectAfter creating the web project or opening an existing web project, You can use VS.NET installer to create a Web Setup project. So do the following steps. Add a Web Setup project to the solution through File/New/Project menu. Choose the Setup and Deployment Projects in Project Types tree control and after that select the Web Setup Project from Templates list box and name it WebSetup. Be aware of select the Add to Solution radio button. 
Now the project is added to the Solution Explorer, and you can see the File System Editor. With File System Editor, you can add files and dependencies to the setup project and configure the location of installation. 
Now you must add project files and dependencies to the setup project. For this reason right click on the Web Application Folder in File System Editor and choose Add/Project Output from the menu (You can do this through Action menu as well). Then select the Primary Output and Content Files from the Add Project Output Group dialog. 
By pressing the OK button the primary output and content files of the TestWeb project will be added to the Application Folder automatically. Also the dependencies are automatically detected in the Solution Explorer. As you can see the dotnetfxredist_x86_enu.msm merge module is added to the WebSetup project. This merge module includes all assemblies of .NET framework. The exclude property of dotnetfxredist_x86_enu.msm is TRUE by default. In our case we suppose that .NET runtime is already installed on the target machine, otherwise you can define .NET Framework Lauch Condition in your setup project. In the properties window, set the DefaultDocument property to "Webform1.aspx" page. It's now time to build your web setup. So right click on WebSetup on Solution Explorer and choose Build. With a successful build, you can find the following files in the Debug or Release directory (depending on your build settings). 
By executing Setup.exe the TestWeb project will be installed on the target system. Since we excluded .NET framework from our setup project, we must install the TestWeb application on the system with .NET framework installed. After installation process you can see TestWeb in IIS directory. About Majid Shahabfar
| Electronic engineering (B.Sc) Nuclear engineering (M.Sc) My programming experience includes Visual C++, MC++, C#, ASP.NET, Web Services and GDI+. I'm developing software application under .NET technology now and I enjoy keeping my skills up-to-date.
Click here to |
출처 : http://www.codeproject.com/aspnet/deployingwebapplications.asp
happy4u
2005. 3. 11. 11:52
2005. 3. 11. 11:52
가이드라인을 완성했습니다. 일단 목표로 했던 내용은 모두 다뤘습니다. 원문이 제법 길기 때문에 파일로 첨부합니다. 소개 (Introduction): 이 문서는 닷넷 프레임워크 기반의 소켓 프로그램을 작성하려는 개발자를 위해 작성되었습니다. 닷넷 개발자는 C/C++ 등으로 작성된 서버/클라이언트와 통신하기 위한 모듈 또는 소프트웨어를 제작해야 하는 상황에 부닥치게 됩니다. 닷넷 환경에서의 소켓 프로그래밍에 익숙하지 않은 개발자는 많은 어려움에 직면하게 됩니다. 이 문서는 다음과 같은 문제점?해결하기 위한 가이드라인을 제시합니다. l 닷넷 환경에서 구조체를 이용한 소켓 통신 구현이 어렵습니다. l 닷넷 환경과 이기종 환경 간의 통신에서는 데이터의 타입 변환을 신중히 생각해야 합니다. l 그밖에 문자열 변환 등에서 부닥치게 되는 예기치 못한 문제들이 있습니다. 또한 닷넷 환경에서 소켓 통신을 할 때 자주 쓰이는 주요 함수 또는 패턴을 기술합니다. 이 문서의 주요 섹션은 다음과 같이 구성되어 있습니다. l 닷넷 환경에서 구조체는 관리되는 메모리 구조를 갖는다. l 닷넷 환경에서의 구조체를 이용한 소켓 통신 구현 방법 l 패킷 송신 방법 l 패킷 수신 방법 l 주요 함수 l 데이터의 변환
happy4u
2005. 3. 3. 10:24
2005. 3. 3. 10:24
Asynchronous Programming in .NET written by Bipin Joshi translated by Asptomorrow
소 개
.NET 프레임워크 에서 비동기 프로그래밍의 지원은 잘 구현되어 있다. 비동기 프로그래밍 모델은 전체 성능을 향상시킬 뿐만아니라 응용프로그램들을 더욱더 응답적이게(responsive) 해준다. 이 강좌에서 비동기 프로그램을 이용하는 컴퍼넌트를 개발하는 완성된 예제를 보여 줄 것이다.
예제에 대해서
우리는 비동기 프로그래밍에 대한 지원을 하는 컴퍼넌트를 작성하는 방법을 보여주는 예제를 만들 것이다. 또한 여러분은 컴퍼넌트를 동기적으로 호출하는 방법을 일반적으로 사용하고 있다는 것을 명심하고, 우리는 직원의 월급을 계산하도록 해주는 간단한 프로그램을 개발할 것이다. 먼저 동기적으로 작동하는 프로그램을 만들어서 잘 작동되는지 알아보고, 조금씩 비동기 프로그래밍 기능을 하도록 추가할 것이다.
컴퍼넌트 생성하기
여러분이 만일 VS.NET 을 사용한다면, C#으로 프로젝트의 새로운 컴퍼넌트 라이브러리 타입을 만들면서 시작할 수 있다. VS.NET을 사용하지 않는다면, Text 에디터에서 .cs 파일을 만들고, 라이브러리(DLL)로 컴파일할 수 있다. 다음 코드는 SalaryCalc 컴퍼넌트를 보여준다.
namespace AsyncProgDemo{public class SalaryCalc{ public SalaryCalc() { } public string Calculate() { Console.WriteLine("Inside Calculate()..."); Console.WriteLine("Caclulating salaries..."); Console.WriteLine("Done..."); return "ok"; }}}
여러분이 위에서 보는 소스는 실제 로직이 들어있지 않은 매우 간단한 코드이다. Salarycalc 라는 클래스를 포함하는 AsyncProgDemo라는 네임스페이스를 만든다. 이 클래스는 한 집단의 모든 직원의 월급을 계산하는 Calculate라는 한개의 메서드를 가지고 있다. 다 마쳐지면 메서드는 "OK" 라는 문자열을 리턴한다.
SalaryCalc 컴퍼넌트를 사용하는 클라이언트 프로그램 만들기
이 컴퍼넌트를 사용하는 콘솔 프로그램을 만들어보자.
using System;namespace AsyncProgDemo{ class Client { static void Main(string[] args) { SalaryCalc sc=new SalaryCalc(); sc.Calculate(); } }}
이 프로그램은 매우 직관적이어서 설명이 필요없을 것이다.
비동기프로그램 컴퍼넌트에 대한 코딩 가이드라인
실제 코딩에 들어가기 전에, 비동기 컴퍼넌트 설계시 추천할만한 가이드라인이 무엇이 있는지 알아보자.
■ 비동기 뿐만 아니라 동기적으로도 메서드를 호출할수 있는 기능 제공
■ 필요에 따라 클라이언트(caller 응용프로그램)이 호출되는 메서드의 버전을 결정할수 있도록 하는 기능
■ 동기적으로 호출한 메서드를 만들기 위해 클라이언트 응용프로그램을 수정하지 않는다. 클라이언트 는 컴퍼넌트에의해 어떻게 호출되는지 모르도록 진행되어야 한다.
비동기프로그램 메서드에 대한 코딩 가이드라인
여러분의 비동기 컴퍼넌트는 메서드를 위해서 다음과 같은 가이드라인을 준수해야한다.
■ 다음과 같은 시그너쳐를 매칭시키는 컴퍼넌트를 작성한다.
□ public XXXX()
□ public IAsyncResult BeginXXXX(AsyncCallback ac, Object state)
□ public EndXXXX(IAsyncResult result)
위의 메서드 중에서 XXXX는 메서드 이름을 나타낸다. 예를들어, 앞에서 본 소스의 경우 Calculate, BeginCalculate, EndCalculate 메서드로 쓸 수 있다. EndXXXX 의 리턴 타입은 여러분의 메서드에서 원했던 리턴타입과 같다. (이 경우 string 일것이다)
BeginXXXX 메서드의 경우 다음과 같은 사항을 기억하자.
■ 모든 IN 파라미터를 포함한다.
■ 모든 OUT 파라니터를 포함한다.
■ 모든 IN/OUT 파라미터를 포함한다.
■ 마지막 두개의 파라미터로 AsyncCallback과 object를 받아들인다.
■ ISyncResult를 리턴한다.
EndXXXX 메서드의 경우 다음과 같은 사항을 기억하자.
■ 모든 IN/OUT 파라미터를 포함한다.
■ 모든 OUT 파라니터를 포함한다.
■ IAsyncResult를 마지막 파라미터로 받아들인다.
■ 여러분이 원하는 데이터 타입으로 값들을 반환한다.
우리가 만든 메서드는 다른 파라미터를 포함하지 않았지만 여러분은 다른 메서드들과 마찬가지 방법을 사용할 수 있다.
네임스페이스 포함시키기
위의 예제가 잘 작동하려면 여러분은 다음과 같은 네임스페이스를 컴퍼넌트에 추가시켜야 한다.
■ System
■ System.Runtime.Remoting.Messaging
SalaryCalc 변형하기
using System;using System.Runtime.Remoting.Messaging;namespace AsyncProgDemo{public class SalaryCalc{public delegate string CalcDelegate();public SalaryCalc(){}public string Calculate(){ Console.WriteLine("Inside Calculate()..."); Console.WriteLine("Caclulating salaries..."); Console.WriteLine("Done..."); return "ok";}public IAsyncResult BeginCalculate(AsyncCallback ac,Object state){ CalcDelegate cd= new CalcDelegate(this.Calculate); IAsyncResult result= cd.BeginInvoke(ac,state); return result;}public string EndCalculate(IAsyncResult result){ CalcDelegate cd=(CalcDelegate) ((AsyncResult)result).AsyncDelegate; object o=cd.EndInvoke(result); return (string)o;}}}
여기서, 원래 클래스에서 몇가지 부분을 추가시켰다.
■ 위에서 언급한 시그너쳐를 매칭시키는 BeginCalculate 메서드를 추가한다.
■ 위에서 언급한 시그너쳐를 매칭시키는 EndCalculate 메서드를 추가한다.
■ BeginCalculate 메서드 내부에서 delegate를 끝냈다. 이 메서드는 컴퍼넌트에서부터 callback 을 받은 후에 클라이언트에 의해 호출될 것이다. callback은 Calculate() 메서드가 종료될때 자동으로 호출된다.
클라이언트의 변형된 버전
이 컴퍼넌트의 비동기적인 특징을 사용하기 위해 우리는 클라이언트를 다음과 같이 바꿀 필요가 있다.
using System;using System.Threading;using System.Runtime.Remoting.Messaging;namespace AsyncProgDemo{class Client{static void Main(string[] args){ SalaryCalc sc=new SalaryCalc(); AsyncCallback ac=new AsyncCallback(MyCallback); IAsyncResult result=sc.BeginCalculate(ac,sc); Thread.Sleep(5000);}public static void MyCallback(IAsyncResult result){SalaryCalc sc=(SalaryCalc)result.AsyncState;object o=sc.EndCalculate(result);Console.WriteLine("Inside Callback...");Console.WriteLine("Result of salary Calculation:" + o);}}}
여기서 Calculate() 메서드를 직접 호출하는 대신에, 우리는 callback 메서드를 호출하는(MyVallback) BeginInvoke 메서드를 호출했고, 결과를 얻었다. 우리는 Calculate 메서드를 직접 호출했을때 같은 결과가 나왔다는 것을 알아두자.
결 론
.NET은 밑바닥에서부터 비동기 프로그래밍을 지원한다. 여러분은 쉽게 함수를 비동기적으로 기능하게 하는 컴퍼넌트를 개발하게 해준다. 앞에서 우리는 그런 컴퍼넌트를 만드는 방법에 대한 예제를 보았고, 또한 그런 컴퍼넌트 개발을 위한 가이드 라인을 알아보았다. |
happy4u
2005. 3. 3. 10:23
2005. 3. 3. 10:23
public delegate int MyDelegate(int i, int j); <- 아래 Add 메소드와 형정보가 같아야 한다. private void button1_Click(object sender, System.EventArgs e) { int i, j; i = Convert.ToInt32(textBox1.Text); j = Convert.ToInt32(textBox2.Text); AsyncCallback ac = new AsyncCallback(CallEnd); <-비동기 콜백 함수 선언 MyDelegate md = new MyDelegate(Add) <- 델리게이트 생성 IAsyncResult ir = md.BeginInvoke(i, j, ac, md); MessageBox.Show("비동기 호출"); /* 직접 호출 int temp = md(i, j); MessageBox.Show(temp.ToString()); */ } public int Add(int i, int j) { System.Threading.Thread.Slepp(5000); <- 5초가 소요되는 코드... return i+j; } public void CallEnd(IAsyncResult ar) { //비동기 결과 출력. MyDelegate md = (MyDelegate) ar.AsyncState; int temp = md.EndInvoke(ar); MessageBox.Show("결과 = "+ temp.ToString()); } ※비동기를 만들기 위해서 1. 비동기 콜백(CallBack) 함수를 만든다. AsyncCallback ac = new AsyncCallback(CallEnd); 2. AsyncCallback도 델리게이트이므로 CallEnd를 선언한다. public void CallEnd(IAsyncResult ar) { } 3. 호출한다. iAsyncResult ir = md.BeginInvoke(i, j, ac, md); "비동기 호출" 메시지 박스 출력 후 5초뒤에 "결과"가 출력된다.
happy4u
2005. 2. 4. 16:22
2005. 2. 4. 16:22
기존의 웹에서 구한 MX Record를 얻어오는 모듈에 문제가 좀 있는 것 같아서 좀 더 찾다가 발견한 글이다. 글 서두에 보면, .Net Framework은 많은 native APIs의 wrapper를 제공하는데, 모두를 제공하는 것은 아니라고 한다. 그래서 MX Record를 얻어오는 빠져있는 것인거 같다. Java의 경우는 JDK에 포함되어 있다고 하던데... 하여간 그래서 아래의 소스는 실제 MX Record를 얻어오는 코드가 아니고, 실제 구현이 되어 있는 'Dnsapi.dll'의 메소드를 call해 주는 소스인 것 같다.
..more
>접기 Build a C# DNS MX (Mail Exchange) Record Query Class by Peter A. Bromberg, Ph.D.
|  |
The .NET Framework provides wrappers to native APIs for a very large number of classes and functions, including the System.Net.Dns classes. However, it doesn't cover all of them. One useful API is the set of DNS query methods in the Dnsapi.dll library, and a particularly useful technique of note is the ability to query a domain and get back the list of MX (Mail Exchange) records of the mail servers associated with the domain. Once you have the code completed to handle this, you will be able to validate an email address against its domain for the mail exchange ("MX") type entries. If there aren't any, then you have a pretty good idea that the email address you are dealing with is BOGUS. Obviously, this can be helpful in tasks such as verifying user registrations on your web site and to fight SPAM. The implementation I provide here is a simplified and very "narrow" one that is intended solely to deal with the MX record lookup. If you want a more complete implementation, there are a number of examples in the Net-o-sphere. One interesting one can be found here. For starters, it might be wise to visit the Platform SDK section on DNS to familiarize ourselves with what we need to create a managed C# PInvoke call to the underlying method. As can be seen, there are three DnsQuery calls, with DnsQuery_W (Unicode) being the most commonly used. There is an fOptions parameter where the types of queries can be combined, the wType type of record parameter, and a ppQueryResultsSet [in, out] pointer parameter. Finally, we are told that we need to free the returned RR Sets with the DnsRecordListFree API call. Note that in the sample code implementation below, VBByRefStr is used for the marshaling directive. The argument is treated as "byref" on the managed side, but stays "byval" on the unmanaged side. If the unmanaged side writes into the buffer, it won't mangle the managed string, which remains immutable. Instead, a different string is propagated to the managed side, preserving managed string immutability. In VB.Net, you could code as if the VBByRefStr is actually byval on the managed side, and the compiler will clean up after you, but in C# you must explicitly add the "ref" keyword in the right places: namespace PAB.DnsUtils{ using System; using System.Collections; using System.ComponentModel; using System.Runtime.InteropServices; public class DnsMx { public DnsMx() { } [DllImport("dnsapi", EntryPoint="DnsQuery_W", CharSet=CharSet.Unicode, SetLastError=true, ExactSpelling=true)] private static extern int DnsQuery([MarshalAs(UnmanagedType.VBByRefStr)]ref string pszName, QueryTypes wType, QueryOptions options, int aipServers, ref IntPtr ppQueryResults, int pReserved); [DllImport("dnsapi", CharSet=CharSet.Auto, SetLastError=true)] private static extern void DnsRecordListFree(IntPtr pRecordList, int FreeType); public static string[] GetMXRecords(string domain) { IntPtr ptr1=IntPtr.Zero ; IntPtr ptr2=IntPtr.Zero ; MXRecord recMx; if (Environment.OSVersion.Platform != PlatformID.Win32NT) { throw new NotSupportedException(); } ArrayList list1 = new ArrayList(); int num1 = DnsMx.DnsQuery(ref domain, QueryTypes.DNS_TYPE_MX, QueryOptions.DNS_QUERY_BYPASS_CACHE, 0, ref ptr1, 0); if (num1 != 0) { throw new Win32Exception(num1); } for (ptr2 = ptr1; !ptr2.Equals(IntPtr.Zero); ptr2 = recMx.pNext) { recMx = ( MXRecord) Marshal.PtrToStructure(ptr2, typeof(MXRecord)); if (recMx.wType == 15) { string text1 = Marshal.PtrToStringAuto(recMx.pNameExchange); list1.Add(text1); } } DnsMx.DnsRecordListFree(ptr2, 0); return (string[]) list1.ToArray(typeof(string)); } private enum QueryOptions { DNS_QUERY_ACCEPT_TRUNCATED_RESPONSE = 1, DNS_QUERY_BYPASS_CACHE = 8, DNS_QUERY_DONT_RESET_TTL_VALUES = 0x100000, DNS_QUERY_NO_HOSTS_FILE = 0x40, DNS_QUERY_NO_LOCAL_NAME = 0x20, DNS_QUERY_NO_NETBT = 0x80, DNS_QUERY_NO_RECURSION = 4, DNS_QUERY_NO_WIRE_QUERY = 0x10, DNS_QUERY_RESERVED = -16777216, DNS_QUERY_RETURN_MESSAGE = 0x200, DNS_QUERY_STANDARD = 0, DNS_QUERY_TREAT_AS_FQDN = 0x1000, DNS_QUERY_USE_TCP_ONLY = 2, DNS_QUERY_WIRE_ONLY = 0x100 } private enum QueryTypes { DNS_TYPE_MX = 15 } [StructLayout(LayoutKind.Sequential)] private struct MXRecord { public IntPtr pNext; public string pName; public short wType; public short wDataLength; public int flags; public int dwTtl; public int dwReserved; public IntPtr pNameExchange; public short wPreference; public short Pad; } }} |
The downloadable sample solution includes a simple Console Tester app that makes the following call: static void Main(string[] args) { string[] s= PAB.DnsUtils.DnsMx.GetMXRecords("microsoft.com"); foreach (string st in s) Console.WriteLine("Server: {0}",st); Console.ReadLine(); which will return the following output: Remember, hamburger@hamburgerhal.com is a valid email address. But, that doesn't mean that you can actually send mail to it. This handy class, along with some good REGEX match strings, should be sufficient to validate most any email address that can be thrown at you. The downloadable solution has more user-friendly exception handling built in. Download the Visual Studio.NET Solution that accompanies this article |
출처 : http://www.eggheadcafe.com/articles/20050129.asp
happy4u
2005. 2. 2. 19:49
2005. 2. 2. 19:49
출처 : http://blogs.msdn.com/brada/articles/361363.aspx
..more
>접기 Table of Contents 1. Introduction.......................................................................................................................................... 1 2. Style Guidelines.................................................................................................................................... 2 2.1 Tabs & Indenting................................................................................................................................ 2 2.2 Bracing............................................................................................................................................... 2 2.3 Commenting........................................................................................................................................ 2 2.3.1 Documentation Comments............................................................................................................. 2 2.3.2 Comment Style............................................................................................................................. 3 2.4 Spacing............................................................................................................................................... 3 2.5 Naming............................................................................................................................................... 4 2.6 Naming Conventions............................................................................................................................ 4 2.6.1 Interop Classes............................................................................................................................. 4 2.7 File Organization................................................................................................................................. 5 First, read the .NET Framework Design Guidelines. Almost all naming conventions, casing rules, etc., are spelled out in this document. Unlike the Design Guidelines document, you should treat this document as a set of suggested guidelines. These generally do not effect the customer view so they are not required. Tab characters (\0x09) should not be used in code. All indentation should be done with 4 space characters. Open braces should always be at the beginning of the line after the statement that begins the block. Contents of the brace should be indented by 4 spaces. For example: if (someExpression) { DoSomething(); } else { DoSomethingElse(); } “case” statements should be indented from the switch statement like this: switch (someExpression) { case 0: DoSomething(); break; case 1: DoSomethingElse(); break; case 2: { int n = 1; DoAnotherThing(n); } break; } Braces should never be considered optional. Even for single statement blocks, you should always use braces. This increases code readability and maintainability. for (int i=0; i<100; i++) { DoSomething(i); } Single line statements can have braces that begin and end on the same line. public class Foo { int bar; public int Bar { get { return bar; } set { bar = value; } } } It is suggested that all control structures (if, while, for, etc.) use braces, but it is not required. 2.4 CommentingComments should be used to describe intention, algorithmic overview, and/or logical flow. It would be ideal, if from reading the comments alone, someone other than the author could understand a function’s intended behavior and general operation. While there are no minimum comment requirements and certainly some very small routines need no commenting at all, it is hoped that most routines will have comments reflecting the programmer’s intent and approach. Each file should start with a copyright notice. To avoid errors in doc comment builds, you don’t want to use triple-slash doc comments, but using XML makes the comments easy to replace in the future. Final text will vary by product (you should contact legal for the exact text), but should be similar to: //----------------------------------------------------------------------- // <copyright file="ContainerControl.cs" company="Microsoft"> // Copyright (c) Microsoft Corporation. All rights reserved. // </copyright> //----------------------------------------------------------------------- 2.4.2 Documentation CommentsAll methods should use XML doc comments. For internal dev comments, the <devdoc> tag should be used. public class Foo { /// <summary>Public stuff about the method</summary> /// <param name=”bar”>What a neat parameter!</param> /// <devdoc>Cool internal stuff!</devdoc> /// public void MyMethod(int bar) { … } } However, it is common that you would want to move the XML documentation to an external file – for that, use the <include> tag. public class Foo { /// <include file='doc\Foo.uex' path='docs/doc[@for="Foo.MyMethod"]/*' /> /// public void MyMethod(int bar) { … } } UNDONE§ there is a big doc with all the comment tags we should be using… where is that? The // (two slashes) style of comment tags should be used in most situations. Where ever possible, place comments above the code instead of beside it. Here are some examples: // This is required for WebClient to work through the proxy GlobalProxySelection.Select = new WebProxy("http://itgproxy");
// Create object to access Internet resources // WebClient myClient = new WebClient(); Comments can be placed at the end of a line when space allows: public class SomethingUseful { private int itemHash; // instance member private static bool hasDoneSomething; // static member } Spaces improve readability by decreasing code density. Here are some guidelines for the use of space characters within code: - Do use a single space after a comma between function arguments.
Right: Console.In.Read(myChar, 0, 1); Wrong: Console.In.Read(myChar,0,1); - Do not use a space after the parenthesis and function arguments
Right: CreateFoo(myChar, 0, 1) Wrong: CreateFoo( myChar, 0, 1 ) - Do not use spaces between a function name and parenthesis.
Right: CreateFoo() Wrong: CreateFoo () - Do not use spaces inside brackets.
Right: x = dataArray[index]; Wrong: x = dataArray[ index ]; - Do use a single space before flow control statements
Right: while (x == y) Wrong: while(x==y) - Do use a single space before and after comparison operators
Right: if (x == y) Wrong: if (x==y)
Follow all .NET Framework Design Guidelines for both internal and external members. Highlights of these include: - Do not use Hungarian notation
- Do not use a prefix for member variables (_, m_, s_, etc.). If you want to distinguish between local and member variables you should use “this.” in C# and “Me.” in VB.NET.
- Do use camelCasing for member variables
- Do use camelCasing for parameters
- Do use camelCasing for local variables
- Do use PascalCasing for function, property, event, and class names
- Do prefix interfaces names with “I”
- Do not prefix enums, classes, or delegates with any letter
The reasons to extend the public rules (no Hungarian, no prefix for member variables, etc.) is to produce a consistent source code appearance. In addition a goal is to have clean readable source. Code legibility should be a primary goal. Classes that are there for interop wrappers (DllImport statements) should follow the naming convention below: - NativeMethods – No suppress unmanaged code attribute, these are methods that can be used anywhere because a stack walk will be performed.
- UnsafeNativeMethods – Has suppress unmanaged code attribute. These methods are potentially dangerous and any caller of these methods must do a full security review to ensure that the usage is safe and protected as no stack walk will be performed.
- SafeNativeMethods – Has suppress unmanaged code attribute. These methods are safe and can be used fairly safely and the caller isn’t needed to do full security reviews even though no stack walk will be performed.
class NativeMethods { private NativeMethods() {} [DllImport(“user32”)] internal static extern void FormatHardDrive(string driveName); }
[SuppressUnmanagedCode] class UnsafeNativeMethods { private UnsafeNativeMethods() {} [DllImport(“user32”)] internal static extern void CreateFile(string fileName); } [SuppressUnmanagedCode] class SafeNativeMethods { private SafeNativeMethods() {} [DllImport(“user32”)] internal static extern void MessageBox(string text); } All interop classes must be private, and all methods must be internal. In addition a private constructor should be provided to prevent instantiation. - Source files should contain only one public type, although multiple internal classes are allowed
- Source files should be given the name of the public class in the file
- Directory names should follow the namespace for the class
For example, I would expect to find the public class “System.Windows.Forms.Control” in “System\Windows\Forms\Control.cs”… - Classes member should be alphabetized, and grouped into sections (Fields, Constructors, Properties, Events, Methods, Private interface implementations, Nested types)
- Using statements should be inside the namespace declaration.
namespace MyNamespace { using System; public class MyClass : IFoo { // fields int foo; // constructors public MyClass() { … } // properties public int Foo { get { … } set { … } } // events public event EventHandler FooChanged { add { … } remove { … } } // methods void DoSomething() { … } void FindSomethind() { … } //private interface implementations void IFoo.DoSomething() { DoSomething(); } // nested types class NestedType { … } } }
happy4u
2005. 1. 25. 16:11
2005. 1. 25. 16:11
소스 안에 주석으로 XML comment를 추가하고, NDOC라는 오픈소스 프로젝트의 프로그램을 이용하여 자동으로 메뉴얼을 만들 수 있다. MSDN 스타일의 뽀대나는 메뉴얼을 거져(?) 얻을 수 있다. 실제 적용할 만한 프로젝트가 있어 적용해 보고자 한다.
..more
>접기 IntroductionMost of us will have experienced the dread of updating documentation at some point or other. C# and Visual Studio .NET (VS.NET) give us the ability to maintain code and documentation in the same file, which makes the whole process a lot easier. VS.NET does this by taking specially marked and structured comments from within the code and building them into an XML file. This XML file can then be used to generate human-readable documentation in a variety of forms including web pages, MSDN style documentation and Intellisense within the code window. Configure XML CommentingVS.NET produces XML comments by taking specially marked and structured comments from within the code and building them into an XML file. This XML file can then be used to generate human-readable documentation in a variety of forms including web pages, MSDN style documentation and Intellisense within the code window. The first thing you need to do is enable the XML commenting feature for your VS.NET project. - Right Click on the project in the solution explorer and select "Properties".
- Within the properties dialog double click on the “Configuration Properties” node.
- The Build node should be already selected and you should be able to see the “XML Documentation File” entry under “Outputs”. Here is where you must enter the name of the XML file that will contain the comment data. You can call the file what you like, but for compatibility with all the features of XML commenting, it should take the form of MyAssemblyName.Xml e.g. Adjuster.BusinessServices.dll has a related XML file called Adjuster.BusinessServices.Xml
With this enabled, your XML comment data file will be rebuilt each time you build your project. Any problems that occur when trying to generate the file will not prevent a build but will be flagged in the VS.NET Task List. Assuming you do not have compile warnings set to errors. 
VS.NET Task List flagging XML commenting error. With that enabled you can start to use the special XML tags in your procedure “headers”. To get you started, place the cursor on the line directly above a procedure’s definition. Once there, press the “/” key three times, this will automatically insert a summary tag into your code. If the procedure had any arguments there should now be a param tag for each one. public void SaveData(ref DataSet data) { } The SaveData code above is what is inserted as default public void SaveData(ref DataSet data) { } This SaveData code is after I have added my comments describing what the routine does in the summary tag and what the data parameter is. This very simple action has given us enough to provide basic documentation including intellisense just like that provided by the .NET Framework assemblies. 
It is clear from just this feature, how useful XML commenting is. When you include a reference to a .NET project that has XML commenting enabled, the XML documentation file we named earlier is copied over along with the binary to the current project’s \bin directory. This gives you the intellisense across assemblies. The summary tag is the most basic of tags. The list below is the complete set currently supported by VS.NET. The ones marked with a * are the ones I feel are the most useful and the ones we will be dealing in the following examples. c The c tag gives you a way to indicate that text within a description should be marked as code. Use code to indicate multiple lines as code.
code * The code tag gives you a way to indicate multiple lines as code. Use <c> to indicate that text within a description should be marked as code.
example * The example tag lets you specify an example of how to use a method or other library member. Commonly, this would involve use of the code tag.
exception * The exception tag lets you specify which exceptions a class can throw.
include The include tag lets you refer to comments in another file that describe the types and members in your source code. This is an alternative to placing documentation comments directly in your source code file.
para The para tag is for use inside a tag, such as <remarks> or <returns> , and lets you add structure to the text.
param * The param tag should be used in the comment for a method declaration to describe one of the parameters for the method.
paramref The paramref tag gives you a way to indicate that a word is a parameter. The XML file can be processed to format this parameter in some distinct way.
permission * The permission tag lets you document the access of a member. The System.Security.PermissionSet lets you specify access to a member.
remarks * The remarks tag is where you can specify overview information about a class or other type. <summary> is where you can describe the members of the type.
returns The returns tag should be used in the comment for a method declaration to describe the return value.
see The see tag lets you specify a link from within text. Use <seealso> to indicate text that you might want to appear in a See Also section.
seealso * The seealso tag lets you specify the text that you might want to appear in a See Also section. Use <see> to specify a link from within text.
summary * The summary tag should be used to describe a member for a type. Use <remarks> to supply information about the type itself.
value * The value tag lets you describe a property. Note that when you add a property via code wizard in the Visual Studio .NET development environment, it will add a <summary> tag for the new property. You should then manually add a <value> tag to describe the value that the property represents.
MSDN Style Documentation and NDOCWe have taken the intellisense format as far as it will go, but there is much more we can do with MSDN style documentation. There is a tool that comes with VS.NET that you will find at “Tools|Build Comment Web Pages…” which will take your C# XML comments from source files and generate linked HTML files. This comes straight out of the box so should not be totally disregarded. But if you want to create easy-to-use, helpful, cross-referenced and attractive documentation, then I can strongly recommend the free, open source tool NDoc. The screenshot below is taken from a compiled help file produced from NDoc and is an example of the quality it can produce. 
The two routines below will show the correct usage for most of the XML comment tags we saw earlier. The cref attribute of the exception tag is used for cross-referencing to an Exception type. This attribute is also used in the seealso , permission and see tags to reference a type. The type must be available from the current compilation environment. The compiler checks that the referenced type exists and passes relevant data to the output XML. public string Age { } This Age property once processed by NDoc will produce this. 
I have drawn attention to areas in the picture and their corresponding XML comment tags. public void SaveData(ref DataSet data) { } This SaveData method once processed by NDoc will produce this 
Again I have drawn attention to areas in the picture and their corresponding XML comment tags. The Accident cross-reference in the “See Also” section is the only one that I added. By default NDoc adds cross-referencing for the parent class, the parent class’ members and the parent class’ namespace. With the combination of NDoc and VS.Net & C#’s ability to produce these comments you can get great technical documentation at a level so close to the code, that there is absolutely no excuse for it not telling it as it is. About Patrick Long
| I have been programming now for 10 years starting with COBOL, CICS and DB2 and ending up with ASP.NET and C#.
I am currently working for Charteris in London. We have a strong partnership with Microsoft UK and I my current project involves working as part of a Microsoft team.
When I am not working i like playing tournament paintball. Click here to view Patrick Long's online profile. |
출처 : http://www.codeproject.com/csharp/csharpcommentinganddocs.asp
happy4u
2005. 1. 23. 11:42
2005. 1. 23. 11:42
아래 그림과 같이 특정 registry의 정보가 바뀌었을 경우 그 내용을 event로 전달받을 수 있게 해 주는 프로그램 특정 application을 작성한 후 config 정보가 변경될 경우 바로 반영되는 작업을 하기에 매우 적당할 듯 
..more
>접기 IntroductionThe Windows API provides a function RegNotifyChangeKeyValue , which notifies the caller about changes to attributes or the content of a specified registry key. Unfortunately, this function is not provided by Microsoft.Win32.RegistryKey class. Because I needed that functionality, I've written a simple wrapper class. UsageThe usage of this is straight forward. First you have to instantiate a RegistryMonitor object. You set its RegistryKey property and subscribe to the monitor's RegChanged event. Now you may start the monitoring by calling Start() . This creates an internal thread running in an endless loop. In this loop, the thread waits for both an event fired by RegNotifyChangeKeyValue and the terminate event, which is set by the Stop() method. Whenever the registry key changes, the RegChanged event is fired. ExampleHere's a console sample monitoring HKCU\Environment (that's where the current user's environment variables are stored): public class MonitorSample{ static void Main() { RegistryMonitor monitor = new RegistryMonitor(); monitor.RegistryKey = Registry.CurrentUser.OpenSubKey(@"Environment", false); monitor.RegChanged += new EventHandler(OnRegChanged); monitor.Start(); while(true); } private void OnRegChanged(object sender, EventArgs e) { Console.WriteLine("registry key has changed"); }} Provided with this article is another demo, which is a WinForm application (however, a VS.NET 2003 solution). Points of interestThe implementation is pretty straightforward. One interesting point is the access to the registry handle. The RegNotifyChangeKeyValue expects a registry handle, but, unfortunately, the handle is a private member of RegistryKey . Well, reflection is your friend: public static IntPtr GetRegistryHandle(RegistryKey registryKey){ Type type = registryKey.GetType(); FieldInfo fieldInfo = type.GetField("hkey", BindingFlags.Instance | BindingFlags.NonPublic); return (IntPtr)fieldInfo.GetValue(registryKey);} History08-Jul-2003 | Initial release |
About Thomas Freudenberg
| Click here to view Thomas Freudenberg's online profile. |
출처 : http://www.codeproject.com/csharp/registrymonitor.asp
happy4u
2005. 1. 23. 11:35
2005. 1. 23. 11:35
제목 그대로...
..more
>접기 Introduction As MFC/SDK programmers move into .NET, what surprises them most is the fact that everything is now so much more easier then ever before. Christian Graus was complaining that it was too easy and that the abominable allowance of gotos annoyed him. He might have a point there, but making coding easy is not such a bad thing after all. It's funny when you think of all the effort Chris Maunder and others put into those MFC & SDK tray icon classes that are ever so popular with copy/paste programmers. I dedicate this article to Chris M and others involved in the brilliant tray icon class project over the last few years. Adding the icon to your project Ctrl-Shift-A will bring up the Add-New-Item dialog box. Select Icon File from the list of available templates. If the list is too populated to your liking select Resources from the tree control on the left. This will bring up a smaller list on the right and it will be easier for you to select Icon File. Now click open. You'll end up with the VS.NET icon editor. You may now create your icon here or copy/paste an icon from elsewhere.
Now right click on this icon from Solution Explorer. Take properties. And change the Build Action property to Embedded Resource. This will instruct the compiler to embed this icon along with your EXE file, thus saving you the annoyance of having to distribute the icon with your EXE.
Adding the NotifyIcon member to your form Okay. Now that we have our icon ready we need to add it to our form class. private NotifyIcon m_notifyicon; Alright, so we have added a NotifyIcon member. Now let's initialize it and set some default properties. This should be done from the form object's constructor. m_notifyicon = new NotifyIcon();m_notifyicon.Text = "Hello, what's cooking?"; m_notifyicon.Visible = true; m_notifyicon.Icon = new Icon(GetType(),"Icon1.ico"); Alright, now compile and run your program. You'll see the icon in your tray. That was rather simple, huh? But usually people like to add a context menu to their tray icons. A tray icon simply sitting there is not very useful. Adding a context menu to the tray icon The first thing we need to do is to add a ContextMenu member to our form. private ContextMenu m_menu; Now we need to initialize it and add some menu items. m_menu = new ContextMenu(); m_menu.MenuItems.Add(0, new MenuItem("Show",new System.EventHandler(Show_Click))); m_menu.MenuItems.Add(1, new MenuItem("Hide",new System.EventHandler(Hide_Click))); m_menu.MenuItems.Add(2, new MenuItem("Exit",new System.EventHandler(Exit_Click))); We have added three menu items and have also associated click event handlers for each of those menu items. I could have created an array of MenuItem objects but that's not really needed here. Now we need to associate this ContextMenu with our tray icon. So we do this. m_notifyicon.ContextMenu = m_menu; Now let's fill up those event handlers. protected void Exit_Click(Object sender, System.EventArgs e) { Close();}protected void Hide_Click(Object sender, System.EventArgs e) { Hide();}protected void Show_Click(Object sender, System.EventArgs e) { Show();} Okay. Compile and run it. Now right clicking on the tray icon brings up the context menu. You can hide and show the form window using the two menu options. And the "Exit" option will exit the application. A small problem Now you'll notice a slight annoyance. The tray icon does not vanish when you exit the program. But when you move the mouse over the tray the icon vanishes. So, what do we do to avoid that? Again as with everything else with this whole .NET thing, it's as easy as 1,2,3. Override your form object's Dispose function and put the following lines of code into it. protected override void Dispose( bool disposing ) { if( disposing ) { this.m_notifyicon.Dispose(); } base.Dispose( disposing );} Full Source Listing using System;using System.Drawing;using System.Windows.Forms;using System.Data;namespace TrayTest{ public class Form1 : System.Windows.Forms.Form { private NotifyIcon m_notifyicon; private ContextMenu m_menu; public Form1() { Text = "TrayIcon test program"; m_menu = new ContextMenu(); m_menu.MenuItems.Add(0, new MenuItem("Show",new System.EventHandler(Show_Click))); m_menu.MenuItems.Add(1, new MenuItem("Hide",new System.EventHandler(Hide_Click))); m_menu.MenuItems.Add(2, new MenuItem("Exit",new System.EventHandler(Exit_Click))); m_notifyicon = new NotifyIcon(); m_notifyicon.Text = "Right click for context menu"; m_notifyicon.Visible = true; m_notifyicon.Icon = new Icon(GetType(),"Icon1.ico"); m_notifyicon.ContextMenu = m_menu; } protected void Exit_Click(Object sender, System.EventArgs e) { Close(); } protected void Hide_Click(Object sender, System.EventArgs e) { Hide(); } protected void Show_Click(Object sender, System.EventArgs e) { Show(); } protected override void Dispose( bool disposing ) { if( disposing ) { this.m_notifyicon.Dispose(); } base.Dispose( disposing ); } [STAThread] static void Main() { Application.Run(new Form1()); } }} Conclusion I would like to thank James Johnson for his valuable tips while I was struggling with embedding icons into my exe. Also a special thanks to Colin for keeping me cheered up with Bobs while I was burying myself in despair after my bad experiences with the new CD writer. About Nishant S 출처 : http://www.codeproject.com/csharp/trayiconmenu01.asp
happy4u
2005. 1. 23. 10:55
2005. 1. 23. 10:55
쩝... 정말 재미있는걸 만드는 사람들이 많다는 생각이 드네요 ^^'' 이 sp는 정말 편할 것 같습니다. Stored Procedure를 C#이나 ASP에서 사용을 할 때, Command Object를 사용하는게 성능에 좋다는 것은 알고 있지만, 지긋지긋한 parameter 객체들을 만들 생각을 하다가 귀찮아서 다른 방식으로 간단하게 사용하는 경우들이 종종 있습니다. 이 sp는 그 문제를 해결해 주네요 ^^'' 
..more
>접기 IntroductionEver got fed up with creating all the code behind parameters for your stored procedures? I have. So, I wrote this stored proc to do the code for me. (I love code that writes code). This has been written for use with "Microsoft Data Application Block" (SQLHelper.cs), however it could be hacked around to write the code without using the MDAB or even to write the code in VB. The script handles both input and output parameters, setting the size of text types, and you could even use it for direct access to a view or table. Using the codeTo implement, just copy the code into Query Analyzer and run. This will create a SPROC called "tools_CS_SPROC_Builder ". To use, just execute the SPROC passing the name of the SPROC you want the code for (see below). Note: don't include any owner prefix, e.g.: (dbo. ). EXEC tools_CS_SPROC_Builder 'mySprocsNameHere' The message window in the Query Analyzer will write out all the code required for your class or code behind. There is a variable in "tools_CS_SPROC_Builder " called "@connName " which you can set to the name of your connection instance. By default, it's set to "conn.Connection " - just alter this for your own project's naming convention. The codeCREATE PROCEDURE tools_CS_SPROC_Builder(@objName nvarchar(100))AS/*___________________________________________________________________Name: CS SPROC BuilderVersion: 1Date: 10/09/2004Author: Paul McKenzieDescription: Call this stored procedue passing the name of your database object that you wish to insert/update from .NET (C#) and the code returns code to copy and paste into your application. This version is for use with "Microsoft Data Application Block". */SET NOCOUNT ONDECLARE @parameterCount intDECLARE @errMsg varchar(100)DECLARE @parameterAt varchar(1)DECLARE @connName varchar(100)//Change the following variable to the name of your connection instanceSET @connName='conn.Connection'SET @parameterAt='' SELECT dbo.sysobjects.name AS ObjName, dbo.sysobjects.xtype AS ObjType, dbo.syscolumns.name AS ColName, dbo.syscolumns.colorder AS ColOrder, dbo.syscolumns.length AS ColLen, dbo.syscolumns.colstat AS ColKey, dbo.systypes.xtypeINTO #t_objFROM dbo.syscolumns INNER JOIN dbo.sysobjects ON dbo.syscolumns.id = dbo.sysobjects.id INNER JOIN dbo.systypes ON dbo.syscolumns.xtype = dbo.systypes.xtypeWHERE (dbo.sysobjects.name = @objName) AND (dbo.systypes.status <> 1) ORDER BY dbo.sysobjects.name, dbo.syscolumns.colorderSET @parameterCount=(SELECT count(*) FROM #t_obj)IF(@parameterCount<1) SET @errMsg='No Parameters/Fields found for ' + @objNameIF(@errMsg is null) BEGIN PRINT 'try' PRINT ' {' PRINT ' SqlParameter[] paramsToStore = new SqlParameter[' + cast(@parameterCount as varchar) + '];' PRINT '' DECLARE @source_name nvarchar,@source_type varchar, @col_name nvarchar(100),@col_order int,@col_type varchar(20), @col_len int,@col_key int,@col_xtype int,@col_redef varchar(20) DECLARE cur CURSOR FOR SELECT * FROM #t_obj OPEN cur FETCH NEXT FROM cur INTO @source_name,@source_type,@col_name,@col_order, @col_len,@col_key,@col_xtype if(@source_type=N'U') SET @parameterAt='@' WHILE @@FETCH_STATUS = 0 BEGIN SET @col_redef=(SELECT CASE @col_xtype WHEN 34 THEN 'Image' WHEN 35 THEN 'Text' WHEN 48 THEN 'TinyInt' WHEN 52 THEN 'SmallInt' WHEN 56 THEN 'Int' WHEN 58 THEN 'SmallDateTime' WHEN 59 THEN 'Real' WHEN 60 THEN 'Money' WHEN 61 THEN 'DateTime' WHEN 62 THEN 'Float' WHEN 99 THEN 'NText' WHEN 104 THEN 'Bit' WHEN 106 THEN 'Decimal' WHEN 122 THEN 'SmallMoney' WHEN 127 THEN 'BigInt' WHEN 165 THEN 'VarBinary' WHEN 167 THEN 'VarChar' WHEN 173 THEN 'Binary' WHEN 175 THEN 'Char' WHEN 231 THEN 'NVarChar' WHEN 239 THEN 'NChar' ELSE '!MISSING' END AS C) PRINT ' paramsToStore[' + cast(@col_order-1 as varchar) + '] = new SqlParameter("' + @parameterAt + @col_name + '", SqlDbType.' + @col_redef + ');' IF(@col_xtype=231)OR(@col_xtype=167)OR(@col_xtype=175) OR(@col_xtype=99)OR(@col_xtype=35) BEGIN PRINT ' paramsToStore[' + cast(@col_order-1 as varchar) + '].Size=' + cast(@col_len as varchar) + ';' END PRINT ' paramsToStore['+ cast(@col_order-1 as varchar) + '].Value = ;' FETCH NEXT FROM cur INTO @source_name,@source_type,@col_name,@col_order, @col_len,@col_key,@col_xtype END PRINT '' PRINT ' SqlHelper.ExecuteNonQuery(' + @connName + ', CommandType.StoredProcedure,"' + @objName + '", paramsToStore);' PRINT ' }' PRINT 'catch(Exception excp)' PRINT ' {' PRINT ' }' PRINT 'finally' PRINT ' {' PRINT ' ' + @connName + '.Dispose();' PRINT ' ' + @connName + '.Close();' PRINT ' }' CLOSE cur DEALLOCATE cur ENDif(LEN(@errMsg)>0) PRINT @errMsgDROP TABLE #t_objSET NOCOUNT ONGOSET QUOTED_IDENTIFIER OFF GOSET ANSI_NULLS ON GO Output Exampletry { SqlParameter[] paramsToStore = new SqlParameter[9]; paramsToStore[0] = new SqlParameter("@organisationid", SqlDbType.BigInt); paramsToStore[0].Value = ; paramsToStore[1] = new SqlParameter("@DisplayName", SqlDbType.NVarChar); paramsToStore[1].Size=100; paramsToStore[1].Value = ; paramsToStore[2] = new SqlParameter("@DefaultCurrencyFID", SqlDbType.Int); paramsToStore[2].Value = ; paramsToStore[3] = new SqlParameter("@TaxCode", SqlDbType.NVarChar); paramsToStore[3].Size=60; paramsToStore[3].Value = ; paramsToStore[4] = new SqlParameter("@UserFID", SqlDbType.BigInt); paramsToStore[4].Value = ; paramsToStore[5] = new SqlParameter("@IsClient", SqlDbType.Bit); paramsToStore[5].Value = ; paramsToStore[6] = new SqlParameter("@IsContractor", SqlDbType.Bit); paramsToStore[6].Value = ; paramsToStore[7] = new SqlParameter("@IsSupplier", SqlDbType.Bit); paramsToStore[7].Value = ; paramsToStore[8] = new SqlParameter("@IsDesigner", SqlDbType.Bit); paramsToStore[8].Value = ; SqlHelper.ExecuteNonQuery(conn.Connection, CommandType.StoredProcedure,"usp_Insert_Organisation", paramsToStore); }catch(Exception excp) { }finally { conn.Connection.Dispose(); conn.Connection.Close(); } All you then have to do is copy-paste and fill in the values you want to pass and catch any exceptions... (Yes you do have to write some code!). Points of InterestIn order for me to work out the @col_xtype variable from sysobjects, I ran lots of tests on a table I created with every type variation in both directions. It certainly works fine for all the usual data types, but I haven't had a chance to test all types within .NET, so if you find a bug, let me know. Enjoy! McCodeJunky
| Click here to view McCodeJunky's |
멋진 사람 ㅋㅋ 출처 : http://www.codeproject.com/cs/database/CSCodeBuilder.asp
happy4u
2005. 1. 17. 15:24
2005. 1. 17. 15:24
쩝... 새해가 되면서 내 나이도 이제 베스킨라빈스... 머리가 나빠진건지... 정규식을 이용해 간단한 도구를 만들고 있는 중이다. 다른 때는 잘 느끼지 못하는데, 특히나 정규식을 할 때 이런 생각이 든다. 항상 간단한 정규식만을 만들어 사용하다가 이번엔 조금 복잡한 만들게 됐다. 까먹지 않고 혹시 나같이 고생하는 사람을 위해... ".... LEFT JOIN..... JOIN...." 다음과 같은 쿼리 문장 중에 JOIN문 앞에서 줄바꿈을 하고 LEFT JOIN의 LEFT 앞에서 줄바꿈을 하려고 했다. 그냥 LEFT JOIN을 줄바꿈+LEFT JOIN으로 바꾸고 JOIN을 줄바꿈+JOIN으로 바꾸면 LEFT JOIN문장은 줄바꿈+LEFT+줄바꿈+JOIN이 된다. 그래서 앞에 LEFT나 RIGHT등이 아닌 JOIN문을 찾아 줄바꿈+JOIN으로 바꾸는 방법이다. 물론 C#을 이용해서 Regex.Replace(str, @"(?<!LEFT\s+|RIGHT\s+|OUTER\s+)(?<end>JOIN)", String.Format("\r\n{0}", "${end}")) Replace의 첫번째 인자는 source, 두번째는 검색할 내용, 세번째는 바꿀 내용이다. 몇일 고생하며 MSDN 뒤지다가 검색한 예제를 보고 알았다. 중요한건 (?<!) ()안의 ?<!뒤에 나오는 내용이 매치되지 않는 스트링을 찾는다는 의미 \s+는 하나 이상의 공백 캐릭터 (?<end>JOIN) 이건 JOIN이고 ?<name>은 name으로 capture해 놓는다는 의미. capture를 해 두면 뒤쪽 replace에서 capture한 내용을 재 사용할 수 있다. 정규식에 대해 전혀 모르는 분은 위의 내용이 무슨 암호로 받아드려지겠지만, 쩝... 정규식 알면 알 수록 신기한 듯 ㅋㅋ
happy4u
2005. 1. 11. 16:48
2005. 1. 11. 16:48
가이드라인을 완성했습니다. 일단 목표로 했던 내용은 모두 다뤘습니다. 원문이 제법 길기 때문에 파일로 첨부합니다. 소개 (Introduction): 이 문서는 닷넷 프레임워크 기반의 소켓 프로그램을 작성하려는 개발자를 위해 작성되었습니다. 닷넷 개발자는 C/C++ 등으로 작성된 서버/클라이언트와 통신하기 위한 모듈 또는 소프트웨어를 제작해야 하는 상황에 부닥치게 됩니다. 닷넷 환경에서의 소켓 프로그래밍에 익숙하지 않은 개발자는 많은 어려움에 직면하게 됩니다. 이 문서는 다음과 같은 문제점을 해결하기 위한 가이드라인을 제시합니다. l 닷넷 환경에서 구조체를 이용한 소켓 통신 구현이 어렵습니다. l 닷넷 환경과 이기종 환경 간의 통신에서는 데이터의 타입 변환을 신중히 생각해야 합니다. l 그밖에 문자열 변환 등에서 부닥치게 되는 예기치 못한 문제들이 있습니다. 또한 닷넷 환경에서 소켓 통신을 할 때 자주 쓰이는 주요 함수 또는 패턴을 기술합니다. 이 문서의 주요 섹션은 다음과 같이 구성되어 있습니다. l 닷넷 환경에서 구조체는 관리되는 메모리 구조를 갖는다. l 닷넷 환경에서의 구조체를 이용한 소켓 통신 구현 방법 l 패킷 송신 방법 l 패킷 수신 방법 l 주요 함수 l 데이터의 변환
happy4u
2005. 1. 5. 11:37
2005. 1. 5. 11:37
조금 더 자세한 자료 출처 : http://www.codeproject.com/dotnet/simplewindowsservice.asp Simple Windows Service Sample By Mahmoud Nasr
A simple application to show how to create a Windows service.
..more
>접기 IntroductionAs a matter of fact Microsoft Windows services, formerly known as NT services enable you to create long-running executable applications that run in its own Windows session, which then has the ability to start automatically when the computer boots and also can be manually paused, stopped or even restarted. This makes services ideal for use on a server or whenever you need long-running functionality that does not interfere with other users who are working on the same computer. You can also run services in the security context of a specific user account that is different from the logged-on user or the default computer account. Windows services don’t have any interface to the user, so it can not be debugged like any regular application, but it’s debugged as a process. .NET has a very nice tool that enables processes debugging while it’s in the run status, by easily pressing Ctrl + Alt + P shortcut. Background I’ve searched well so many sites about a code that I can with the help of it, build a simple Windows service, but I found a lot of code on how to manage the current Windows services of the system and that’s through the ServiceController class. After searching the MSDN, I’ve found some nice code that helped me to create this simple Windows service. Hope it can help as a basic architecture for and usage of such a Windows service. Using the codeAt first you should simply open VS.NET and then at the File menu click on New, Project. From the New Project Dialog Box, choose the Windows service template project and name it MyNewService like shown below: 
The project template automatically adds a component class that is called Service1 by default and inherits from System.ServiceProcess.ServiceBase . Click the designer. Then, in the Properties window, set the ServiceName property for Service1 to MyNewService . Set the Name property to MyNewService . Set the AutoLog property to true . In the code editor, edit the Main method to create an instance of MyNewService . When you renamed the service in step 3, the class name was not modified in the Main method. To access the Main method in VC#, expand the Component Designer generated code region. static void Main(){ System.ServiceProcess.ServiceBase[] ServicesToRun; ServicesToRun = new System.ServiceProcess.ServiceBase[] { new MyNewService() }; System.ServiceProcess.ServiceBase.Run(ServicesToRun); } In the next section, you will add a custom event log to your Windows service. Event logs are not associated in any way with Windows services. Here the EventLog component is used as an example of the type of components you could add to a Windows service. To add custom event log functionality to your service: - In the Solution Explorer, right-click Service1.vb or Service1.cs and select View Designer.
- From the Components tab of the Toolbox, drag an
EventLog component to the designer. - In the Solution Explorer, right-click Service1.vb or Service1.cs and select View Code.
- Edit the constructor to define a custom event log.
To access the constructor in Visual C#, expand the Component Designer generated code region. public MyNewService(){ InitializeComponent() if(!System.Diagnostics.EventLog.SourceExists("DoDyLogSourse")) System.Diagnostics.EventLog.CreateEventSource("DoDyLogSourse", "DoDyLog"); eventLog1.Source = "DoDyLogSourse"; eventLog1.Log = "DoDyLog";} To define what happens when the service starts, in the code editor, locate the OnStart method that was automatically overridden when you created the project, and write code to determine what occurs when the service begins running: protected override void OnStart(string[] args){ eventLog1.WriteEntry("my service started"); } The OnStart method must return to the operating system once the service's operation has begun. It must not loop forever or block. To set up a simple polling mechanism, you can use the System.Timers.Timer component. In the OnStart method, you would set parameters on the component, and then you would set the Timer.Enabled property to true . The timer would then raise events in your code periodically, at which time your service could do its monitoring. To define what happens when the service is stopped, in the code editor, locate the OnStop procedure that was automatically overridden when you created the project, and write code to determine what occurs when the service is stopped: protected override void OnStop(){ eventLog1.WriteEntry("my service stoped");} You can also override the OnPause , OnContinue , and OnShutdown methods to define further processing for your component. For the method you want to handle, override the appropriate method and define what you want to occur. The following code shows what it looks like if you override the OnContinue method: protected override void OnContinue(){ eventLog1.WriteEntry("my service is continuing in working");} Some custom actions need to occur when installing a Windows service, which can be done by the Installer class. Visual Studio can create these installers specifically for a Windows service and add them to your project. To create the installers for your service. - Return to design view for
Service1 . - Click the background of the designer to select the service itself, rather than any of its contents.
- In the Properties window, click the Add Installer link in the gray area beneath the list of properties. By default, a component class containing two installers is added to your project. The component is named
ProjectInstaller , and the installers it contains are the installer for your service and the installer for the service's associated process. - Access design view for
ProjectInstaller , and click ServiceInstaller1 . - In the Properties window, set the
ServiceName property to MyNewService . - Set the
StartType property to Automatic .
TipTo avoid being asked about the system username and password you must change the Account for the serviceProcessInstaller to LocalSystem . This is done by opening the ProjectInstaller design and then selecting the serviceProcessInstaller , press F4 and then change the Account property to LocalSystem . Or you can manually do that by creating a class that inherits from System.Configuration.Install.Installer like this: [RunInstaller(true)]public class ProjectInstaller : System.Configuration.Install.Installer private System.ServiceProcess.ServiceProcessInstaller serviceProcessInstaller1;private System.ServiceProcess.ServiceInstaller serviceInstaller1; public ProjectInstaller() InitializeComponent(); } private void InitializeComponent() { this.serviceProcessInstaller1 = new System.ServiceProcess.ServiceProcessInstaller(); this.serviceInstaller1 = new System.ServiceProcess.ServiceInstaller(); this.serviceProcessInstaller1.Account = System.ServiceProcess.ServiceAccount.LocalSystem; this.serviceProcessInstaller1.Password = null; this.serviceProcessInstaller1.Username = null; this.serviceInstaller1.ServiceName = "MyNewService"; this.serviceInstaller1.StartType = System.ServiceProcess.ServiceStartMode.Automatic; this.Installers.AddRange (new System.Configuration.Install.Installer[] { this.serviceInstaller1, this.serviceInstaller1}); }} To build your service project- In Solution Explorer, right-click your project and select Properties from the shortcut menu. The project's Property Pages dialog box appears.
- In the left pane, select the General tab in the Common Properties folder.
- From the
Startup object list, choose MyNewService . Click OK. - Press Ctrl+Shift+B to build the project.

Now that the project is built, it can be deployed. A setup project will install the compiled project files and run the installers needed to run the Windows service. To create a complete setup project, you will need to add the project output, MyNewService.exe, to the setup project and then add a custom action to have MyNewService.exe installed. To create a setup project for your service- On the File menu, point to Add Project, and then choose New Project.
- In the Project Types pane, select the Setup and Deployment Projects folder.
- In the Templates pane, select Setup Project. Name the project
MyServiceSetup .
A setup project is added to the solution. Next you will add the output from the Windows service project, MyNewService.exe, to the setup. 
To add MyNewService.exe to the setup project- In Solution Explorer, right-click
MyServiceSetup , point to Add, then choose Project Output. The Add Project Output Group dialog box appears. MyNewService is selected in the Project box. - From the list box, select Primary Output, and click OK.
A project item for the primary output of MyNewService is added to the setup project. Now add a custom action to install the MyNewService.exe file.
To add a custom action to the setup project- In Solution Explorer, right-click the setup project, point to View, then choose Custom Actions. The Custom Actions editor appears.
- In the Custom Actions editor, right-click the Custom Actions node and choose Add Custom Action. The Select Item in Project dialog box appears.
- Double-click the application folder in the list box to open it, select primary output from
MyNewService (Active), and click OK. The primary output is added to all four nodes of the custom actions — Install, Commit, Rollback, and Uninstall. - Build the setup project.
To install the Windows ServiceBrowse to the directory where the setup project was saved, and run the .msi file to install MyNewService.exe. 
To start and stop your service- Open the Services Control Manager by doing one of the following:
- You should now see
MyNewService listed in the Services section of the window. - Select your service in the list, right-click it, and then click Start.
Right-click the service, and then click Stop. 
To verify the event log output of your service- Open Server Explorer and access the Event Logs node. For more information, see Working with Event Logs in Server Explorer.
Note: The Servers node of Server Explorer is not available in the Standard Edition of Visual Basic and Visual C# .NET. 
To uninstall your service- On the Start menu, open Control Panel and click Add/Remove Programs, and then locate your service and click Uninstall.
- You can also uninstall the program by right-clicking the program icon for the .msi file and selecting Uninstall.
happy4u
2005. 1. 5. 11:35
2005. 1. 5. 11:35
VS .Net으로 Windows Service를 만드는 방법 출처 : http://www.c-sharpcorner.com/2/window_service.asp
..more
>접기 NOTE: Ok, I am being lazy here. The project name in this sample code is mcWebService which is a spell mistake. I meant to put mcWinService. And now I don't want to change all the screen shots and code all over again. I hope it won't confuse you :). Ok, its time for one more tutorial. This times pick is Windows Services. Creating Windows Services is not a big deal using Visual C#. Just follow few simple steps and you are all set to run and test your first Windows Service. Windows Services is new name for NT Services you used to develop in previous versions of Visual Studio. This tutorial walks you through how to create and use your Windows Services. This Service writes some text to a text file when stop and start the service. The base idea is taken from MSDN but its more elaborated. You can modify it according to your needs. Step 1. Create Skeleton of the Service To create a new Window Service, pick Windows Service option from your Visual C# Projects, give your service a name, and click OK. 
The result look like this. The Wizard adds WebService1.cs class to your project. 
Set your ServiceName to your own name so it would be easier to recognize your service during testing OR you can set this property programmatically using this line this.ServiceName = "mcWinService"; This is the name you will be looking for later :). 
The default code of WebService1.cs added by the Wizard looks like here - namespace mcWebService
- {
- using System;
- using System.Collections;
- using System.Core;
- using System.ComponentModel;
- using System.Configuration;
- using System.Data;
- using System.Web.Services;
- using System.Diagnostics;
- using System.ServiceProcess;
- public class WinService1 : System.ServiceProcess.ServiceBase
- {
- /// <summary>
- /// Required designer variable.
- /// </summary>
- private System.ComponentModel.Container components;
- public WinService1()
- {
- // This call is required by the WinForms Component Designer.
- InitializeComponent();
- // TODO: Add any initialization after the InitComponent call
- }
- // The main entry point for the process
- static void Main()
- {
- System.ServiceProcess.ServiceBase[] ServicesToRun;
-
- // More than one user Service may run within the same process. To add
- // another service to this process, change the following line to
- // create a second service object. For example,
- //
- // ServicesToRun = New System.ServiceProcess.ServiceBase[] {new WinService1(), new MySecondUserService()};
- //
- ServicesToRun = new System.ServiceProcess.ServiceBase[] { new WinService1() };
- System.ServiceProcess.ServiceBase.Run(ServicesToRun);
- }
- /// <summary>
- /// Required method for Designer support - do not modify
- /// the contents of this method with the code editor.
- /// </summary>
- private void InitializeComponent()
- {
- components = new System.ComponentModel.Container();
- this.ServiceName = "WinService1";
- }
- /// <summary>
- /// Set things in motion so your service can do its work.
- /// </summary>
- protected override void OnStart(string[] args)
- {
- // TODO: Add code here to start your service.
- }
-
- /// <summary>
- /// Stop this service.
- /// </summary>
- protected override void OnStop()
- {
- // TODO: Add code here to perform any tear-down necessary to stop your service.
- }
- }
- }
|
Step 2. Add functionality to your service As you saw WebService1.cs, there are two overridden functions OnStart and OnStop. The OnStart function executes when you start your service and the OnStop function gets execute when you stop a service. I write some text to a text file when you start and stop the service. - protected override void OnStart(string[] args)
- {
- FileStream fs = new FileStream(@"c:\temp\mcWindowsService.txt" , FileMode.OpenOrCreate, FileAccess.Write);
- StreamWriter m_streamWriter = new StreamWriter(fs);
- m_streamWriter.BaseStream.Seek(0, SeekOrigin.End);
- m_streamWriter.WriteLine(" mcWindowsService: Service Started \n");
- m_streamWriter.Flush();
-
- }
-
- /// <summary>
- /// Stop this service.
- /// </summary>
- protected override void OnStop()
- {
- FileStream fs = new FileStream(@"c:\temp\mcWindowsService.txt" , FileMode.OpenOrCreate, FileAccess.Write);
- StreamWriter m_streamWriter = new StreamWriter(fs);
- m_streamWriter.BaseStream.Seek(0, SeekOrigin.End);
- m_streamWriter.WriteLine(" mcWindowsService: Service Stopped \n");
- m_streamWriter.Flush();
- }
|
Step 3: Install and Run the Service Build of this application makes one exe, mcWinService.exe. You need to call installutil to register this service from command line. installutil C:\mcWebService\bin\Debug\mcWebService.exe You use /u option to uninstall the service. installutil /u C:\mcWebService\bin\Debug\mcWebService.exe Run the application Step 4: Start and Stop the Service You need to go to the Computer Management to Start to start and stop the service. You can use Manage menu item by right clicking on My Computer. 
Under Services and Applications, you will see the service mcWinService. Start and Stop menu item starts and stops the service. 
Step 5: Test the Service Go to your temp directory and see if text file is there with contents or not. That's it. Feedback: Please post all of your feedback on C# Corner discussion forums. References:
happy4u
2005. 1. 1. 11:49
2005. 1. 1. 11:49
ArrayList 클래스의 매개 변수 없는 ToArray 메서드는 Object 형식의 배열을 반환합니다. Object 배열을 사용자 형식의 배열로 캐스팅할 때는 ToArray의 매개 변수 없는 구현을 사용할 수 없습니다. 예를 들어 ArrayList에 Customer 개체를 몇 개 추가하면 기본 목록이 Customer 배열로 만들어지지 않습니다. 따라서 다음 문은 System.InvalidCastException 예외와 함께 실패합니다. Customer [] customer = (Customer[])myArrayList.ToArray(); 강력하게 형식화된 배열을 반환하려면 개체 형식을 매개 변수로 받아들이는 오버로드된 ToArray 메서드를 사용하십시오. 예를 들어 다음 문은 성공합니다. Customer [] customer = (Customer[])myArrayList.ToArray(typeof(Customer)); 참고: C#에서는 암시적 캐스팅이 허용되지 않으므로 ToArray 메서드의 결과를 명시적으로 캐스팅해야 합니다.
중요: ArrayList의 요소는 개체 형식이 모두 같아야 합니다. 다른 개체로 이루어진 ArrayList를 특정 형식으로 캐스팅하려고 하면 ToArray 메서드가 실패합니다.
단계별 예제 using System; using System.Collections; class Class1 { [STAThread] static void Main(string[] args) { customer c = new customer(); c.cname = "anonymous"; ArrayList al=new ArrayList(); al.Add(c); object[] cArray = al.ToArray(); //Display the type of the ArrayList. Console.WriteLine(cArray.GetType()); //customer[] custArray = (customer[])(al.ToArray());
//InvalidCastException 예외를 재현하려면 위의 주석문을 해제하고. // 아래 명령을 주석처리 하여 실행하십시오. customer[] custArray = (customer[])al.ToArray(typeof(customer));
Console.WriteLine(custArray.GetType()); } } class customer { public string cname; } 자료출처 : http://support.microsoft.com/
happy4u
2005. 1. 1. 11:38
2005. 1. 1. 11:38
Asynchronous Socket Programming in C#Client-Server Example with Multiple Simultaneous ClientsEnvironment: C#, Windows
ObjectiveThe objective of this article is to demonstrate a socket-based client/server application that will allow two-way asynchronous communication between a server and multiple client applications. Because this example uses asynchronous methods, the server application does not use threads to communicate to multiple clients (although internally the asynchronous communication mechanism uses threads at the OS level).
..more
>접기 Difference Between Synchronous and Asynchronous Communication in Network Programming The key difference between synchronous and asynchronous communication can be explained with an example. Consider a server application that is listening on a specific port to get data from clients. In synchronous receiving, while the server is waiting to receive data from a client, if the stream is empty then the main thread will block until the request for data is satisfied. Hence, the server cannot do anything else until it receives data from the client. If another client attempts to connect to the server at that time, the server cannot process that request because it is blocked on the first client. This behavior is not acceptable for a real-world application where we need to support multiple clients at the same time. In asynchronous communication, while the server is listening or receiving data from a client, it can still process connection requests from other clients as well as receive data from those clients. When a server is receiving asynchronously, a separate thread (at the OS level) listens on the socket and will invoke a callback function (specified when the asynchronous listening was commenced) when a socket event occurs. This callback function in turn will respond and process that socket event. For example, if the remote program writes some data to the socket, a "read data event" (callback function we specify) is invoked which knows how to read the data from the socket at that point. Even though this could be achieved by running multiple threads, the C# and .NET frameworks provide us with a rich set of functionalities to do asynchronous communications without introducing the complexity of threading. Socket ClassThe Socket class (System.Net.Sockets.Socket) provides a set of synchronous and asynchronous methods for synchronous or asynchronous communication. As per the .NET naming convention, all the asynchronous method names are created by prefixing the words "Begin" or "End" to the name of the synchronous methods. The methods prefixed with "Begin" and "End" represent a pair of asynchronous methods corresponding to a single synchronous method, as shown in the following table. Synchronous Methods | Asynchronous Methods | Connect() | BeginConnect() EndConnect() | Receive() | BeginReceive() EndReceive() |
Example ApplicationThe example shown in this article has two classes, one implementing the Socket Server and the other implementing the Socket Client. Socket Server Implementation
The Socket Server application is implemented in the SocketServer class (file name SocketServer.cs). This class has a main Socket object (m_mainSocket) and an array of worker Socket objects (m_workerSocket) as members. The main Socket object does the listening for the clients. Once a client is connected, the main Socket transfers the responsibility to process the transactions related to that particular client to a worker Socket. Then, the main Socket goes back and continues listening for other clients. BeginAccept() and BeginReceive() are the two important methods in the Socket class used by the Socket Server application. The BeginAccept() method has the following signature: public IAsyncResult BeginAccept( AsyncCallback callback, object state ); Essentially, after calling the Listen() method of the main Socket object, we call this asynchronous method and specify a call back function (1), which we designated to do the further processing related to the client connection. The state object (2) can be null in this particular instance. Because this is an asynchronous method, it will return immediately and the server main thread is free to process other events. Behind the scenes, a separate thread will start listening on that particular socket for client connections. When a client requests a connection, the callback function we specified will be invoked. Inside the callback function (in our example, the function is named "OnClientConnect()"), we will do further processing related to the client connection. public void OnClientConnect(IAsyncResult asyn) { try { m_workerSocket[m_clientCount] = m_mainSocket.EndAccept (asyn); WaitForData(m_workerSocket[m_clientCount]); ++m_clientCount; String str = String.Format("Client # {0} connected", m_clientCount); textBoxMsg.Text = str; m_mainSocket.BeginAccept(new AsyncCallback ( OnClientConnect ),null); } catch(ObjectDisposedException) { System.Diagnostics.Debugger.Log(0,"1","\n OnClientConnection: Socket has been closed\n"); } catch(SocketException se) { MessageBox.Show ( se.Message ); } } The first thing we do inside the "OnClientConnect()" function is to call the EndAccept() method on the m_mainSocket member object, which will return a reference to another socket object. We set this object reference to one of the members of the array of Socket object references we have (m_workerSocket) and also increment the client counter. Now, because we have a reference to a new socket object that now can do the further transaction with the client, the main Socket (m_mainSocket) is free; hence, we will call its BeginAccept() method again to start waiting for connection requests from other clients. On the worker socket, we use a similar strategy to receive the data from the client. In place of calling BeginAccept() and EndAccept(), here we call BeginReceive() and EndReceive(). This, in a nutshell, is the Socket Server implementation. While we are sending out data to the clients, the server simply uses the specific worker socket objects to send data to each client. Socket Client Implementation (Full Size Image)
The Socket Client application is implemented in the SocketClient class (file name SocketClient.cs). Compared to the server where we have a main Socket and an array of worker Sockets, here we only have a single Socket object (m_clientSocket). The two important methods in Socket class used by the Socket Client application are the Connect() and BeginReceive() method. Connect() is a synchronous method and is called to connect to a server that is listening for client connections. Because this call will succeed/fail immediately, depending on whether there is an active server listening or not at the specified IP and Port number, a synchronous method is okay for this purpose. Once a connection is established, we call the BeginReceive() asynchronous function to wait for any socket write activity by the server. Here, if we call a synchronous method, the main thread on the client application will block and we will not be able to send any data to the server while the client is waiting for data from the server. When there is any write activity on the socket from the server end, the internal thread started by BeginReceive() will invoke the callback function ("OnDataReceived()" in our case), which will take care of the further processing of the data written by the server. When sending the data to the server, we just call the Send() method on the m_clientSocket object, which will synchronously write the data to the socket. That is all there is for asynchronous socket communication using multiple clients. Limitations/Possible Improvements- Up to 10 simultaneous clients are supported. You can easily modify and support unlimited number of clients by using a HashTable instead of an array.
- For simplicity, when the server sends out a message, it is broadcast to all the connected clients. This could easily be modified to send messages to specific clients by using the Socket object pertaining to that particular client.
- When a client is disconnected, proper action is not taken; the client count is not decremented. The correct way would be to reuse or release resources for other client connections.
Downloads
async_client_server_exe.zip - Windows Executable Files async_client_server_src.zip - C# Source Code
happy4u
2004. 12. 23. 15:16
2004. 12. 23. 15:16
.NET Enterprise Services 성능Richard Turner, 프로그램 관리자, XML Enterprise Services Larry Buerk, 프로그램 관리자, XML Enterprise Services Dave Driver, 소프트웨어 디자인 엔지니어, XML Enterprise Services Microsoft Corporation 2004년 3월 적용 대상: COM+ 구성 요소 Microsoft .NET Enterprise Services 요약: 다른 활성화 및 호출 패턴에 적용될 때의 원시 COM+ 및 .NET Enterprise Services 구성 요소 성능을 확인합니다. .NET Enterprise Services 구성 요소를 C++의 COM+ 구성 요소처럼 빨리 실행하기 위한 지침과 함께 고성능 .NET Enterprise Service 구성 요소를 만드는 데 도움이 되는 주요 권장 사항을 살펴봅니다(45페이지/인쇄 페이지 기준). 관련 EnterpriseServicesPerf.exe 코드 샘플을 다운로드하십시오. 목차소개 관리되는 코드로 마이그레이션해야 하는 이유 코드 변경 정도 지정 .NET Enterprise Services에 COM+ 연결 .NET Enterprise Services와 COM+ 성능 비교 테스트 결과 및 분석 결론 부록 1: 성능 권장 사항 부록 2: "Indigo" 및 .NET의 동향 부록 3: 분산 트랜잭션이 성능에 미치는 영향 부록 4: 참고 자료 부록 5: 성능 테스트 소스 코드 부록 6: 테스트 결과 |
..more
>접기 소개COM+ 코드를 "원시" Visual C++ 또는 Visual Basic 6에서 관리되는 .NET Enterprise Services 구성 요소로 이동할 것을 고려 중인 개발자는 다음과 같은 고민 사항이 있을 수 있습니다. - 왜 관리되는 코드로 전환해야 하는가?
- 코드를 얼마나 변경해야 하는가?
- Enterprise Services 구성 요소는 어떻게 수행되는가?
- COM+ 및 .NET Enterprise Services가 제시하는 미래는 어떠한가?
이 문서에서는 특히 성능에 대한 질문을 위주로 위 주제를 다룰 것입니다. 이러한 주제에 대한 자세한 내용은 부록 4: 참고 자료에 있는 리소스를 참조하십시오. 이 문서는 COM+ 구성 요소를 개발하고 코드를 .NET Enterprise Services로 마이그레이션할 것을 고려 중인 개발자와 설계자를 대상으로 합니다. 관리되는 코드로 마이그레이션해야 하는 이유개발자가 .NET에서 코드를 개발해야 하는 이유는 여러 가지입니다. 다음은 코드 개발의 몇 가지 이점입니다. - 향상된 개발자 생산성: 개발자들은 종종 .NET을 사용하여 개발할 때 작성해야 하는 "통로 코드"가 훨씬 적기 때문에 응용 프로그램 논리를 작성하는 데 더 많은 신경을 쓸 수 있습니다. 또한 대부분의 개발자는 .NET에서 제공하는 명확하고 일관되게 구성된 풍부한 리소스 라이브러리 덕분에 다른 기술과 비교하여 훨씬 빨리 배울 수 있습니다.
- 향상된 코드 안정성 및 보안: 개발자는 원시 코드보다는 .NET을 사용할 때 안정적이고 보안된 코드를 더욱 쉽게 작성할 수 있습니다. 그 이유는 코드 액세스 보안 및 CLR(공용 언어 런타임) 같은 기능 때문입니다. 이러한 기능은 NET 코드가 다른 실행 중인 코드에 의도하지 않은 영향을 미치는 것을 방지하고 해커가 .NET 코드를 사용하여 환경을 방해하거나 제어할 수 있는 기회를 줄이는 데 도움이 됩니다.
- 향상된 성능 및 확장성: 개발자는 .NET으로 마이그레이션할 때 코드의 성능과 확장성이 향상되는 것을 알 수 있습니다. 모든 .NET 언어가 다중 스레딩 같은 기능을 지원하고 활용하기 때문입니다.
- XCOPY 배포: 대부분의 .NET 응용 프로그램에서는 필요한 파일을 하드 드라이브의 폴더로 복사하고 공유 구성 요소를 운영 체제에 선택적으로 등록하기만 하면 배포가 이루어집니다. 이는 다른 응용 프로그램에서 일반적으로 사용하는 것보다 훨씬 명쾌한 배포 전략입니다.
개발자가 .NET으로 마이그레이션하기를 원하는 10가지 이유에 대해서는 Top 10 Reasons for Developers to Use the .NET Framework 1.1 을 참조하십시오. .NET은 시스템 관리자에게도 이점을 제공합니다. 관리자가 .NET으로 이동하기를 원하는 10가지 이유가 기록된 목록을 보려면 Top 10 Reasons for Systems Administrators to Use the .NET Framework 1.1 을 참조하십시오. 일반 C++ 코드를 관리되는 C++로 마이그레이션하는 방법에 대한 소개는 Managed Extensions for C++ Migration Guide의 Introduction to Wrapping C++ Classes 를 참조하십시오. 코드 변경 정도 지정대부분의 경우 COM+ 코드를 .NET Enterprise Services에 연결하려면 COM+ 구성 요소가 어떠한 언어로 개발되었는지를 비롯한 다수의 요인에 따라 몇 가지 수동 작업이 필요합니다. 예를 들어, Visual Basic 6 개발자는 앞으로 나올 Visual Studio 2005의 도구에서 서브루틴 및 함수의 본문을 수정하지 않고도 클래스 정의 및 메서드 서명을 변환할 수 있는 몇 가지 지원을 받게 됩니다(다른 변환된 메서드에 대한 호출은 제외). C++ 개발자는 COM+ 코드에서 .NET 코드로 변환하는 작업을 대부분 수동으로 수행해야 하지만, 대부분의 통로가 ATL(Active Template Library) 같은 클래스 라이브러리 대신 CLR에 구현되기 때문에 변환된 코드가 좀 더 간결해지는 것을 확인할 수 있습니다. C++ 개발자는 응용 프로그램을 연결할 언어를 선택할 수도 있습니다. 예를 들어, 기존 코드 기반을 최대한 활용하기 위해 관리되는 C++를 선택하거나, 더욱 간결한 코드를 위해 C#을 선택할 수 있습니다. .NET Enterprise Services에 COM+ 구성 요소 연결기존 COM+ 코드를 Visual Basic 6 및 Visual C++ 같은 원시 프로그래밍 언어와 도구로부터 마이그레이션하는 개발자는 .NET 코드로 완벽하게 변환하기 위해 몇 가지 기존 코드를 수정해야 합니다. 여기에 동반되는 작업 양은 사용할 수 있는 기존 코드 기반 및 도구에 따라 다릅니다. 다음 표에는 코드를 .NET으로 마이그레이션할 때 고려할 옵션이 요약되어 있습니다. 변환하기 전의 언어 | 변환한 후의 언어 | 코드 변환 도구 사용 가능 여부 | 필요한 코드 변환 작업 |
---|
Visual Basic 6 | Visual Basic .NET | 예(Visual Studio 2005) | 대부분의 Visual Basic 6 코드는 Visual Basic .NET에 직접 연결됩니다. Visual Studio 2005의 Visual Basic 6 코드 마이그레이션 도구는 대부분의 클래스와 메서드 선언 및 형식을 Visual Basic .NET 구문으로 변환합니다. | Visual C++ | Visual C++ .NET | 아니요 | C++ .NET은 특히 원시 코드와 .NET 사이에서 상호 작동하는 코드를 작성하는 데 유용합니다. | Visual C++ | Visual C# | 아니요 | C# 구문은 많은 면에서 C++와 비슷합니다. 변환을 수행하려면 개발자의 특정 작업이 필요합니다. |
.NET 특성COM+ 구성 요소를 설치한 후에는 구성 요소 서비스 스냅인 도구를 사용하여 수동으로 구성하거나 스크립트 또는 코드를 통해 구성해야 합니다. 예를 들어, 구성 요소에 트랜잭션 지원이 필요하다고 표시하고 각 구성 요소의 AddSale() 메서드가 오류 없이 완료될 경우 트랜잭션을 자동으로 커밋하도록 지정하는 상황을 가정합니다. 그러기 위해서는 구성 요소 및 필요한 메서드의 속성을 COM+ 구성 요소 서비스 관리 콘솔에서 수동으로 구성해야 합니다. - 구성 요소 서비스 관리 콘솔을 열고 올바른 응용 프로그램 및 구성 요소를 탐색합니다.
- 이 구성 요소의 속성을 열고 트랜잭션 탭을 클릭한 다음 필수를 클릭합니다.
- 확인을 클릭하고 구성 요소 탐색기를 통해 ATLPerfTests 개체의 AddSale() 메서드를 찾습니다.
- AddSale() 메서드를 마우스 오른쪽 단추로 클릭하고 메서드의 속성을 연 다음 이 메서드가 반환하면 자동으로 이 개체 비활성화 확인란을 선택합니다.
관리자는 일반적으로 보안 및 ID 설정 같은 배포 지향 설정이나 역할 구성원 및 재활용 같은 런타임 지향 설정을 구성합니다. 개발자는 트랜잭션 지원과 같은 구성 요소의 개발 지향 기능을 구성합니다. 그러나 COM+에서는 개발자가 코드 내에서 구성 요소의 구성 방법을 지정하기가 어렵습니다. Visual Basic 개발자는 구성 요소에 필요한 트랜잭션 지원을 어느 정도 지정할 수 있지만 C++ 개발자는 그렇지 못합니다. COM+ 구성 요소를 안정적이면서 반복적으로 설치하기 위해서는 스크립트, 설치 관리자 응용 프로그램 또는 설치 지침을 작성해야 합니다. .NET은 개발자가 구성 요소의 코드 내에서 구성 요소에 필요한 서비스와 해당 서비스의 구성 방법을 지정할 수 있도록 함으로써 구성 요소 구성을 단순화합니다. 구성 요소가 설치되면 플랫폼에서 구성 설정을 자동으로 구성하지만, 이러한 구성 설정은 설치 후에 변경할 수 있습니다. COM+에서는 설치 후에 구성 설정을 변경할 수 있기 때문에 이러한 속성을 다수 변경할 때는 매우 주의를 기울여야 합니다. 예를 들어, 보안 설정을 변경하면 개체를 인스턴스화하고 개체의 메서드를 호출할 수 있는지의 권한 지정에 영향을 미칠 수 있습니다. 반면에 트랜잭션 지원을 제거하면 구성 요소가 안정적이지 못하고 예측 불가능해질 수 있으며 구성 요소의 데이터가 손실되거나 손상될 수도 있습니다. 개발자는 특성(C# 및 C++에서는 [attribute]와 같이 대괄호 안에 표시되고, Visual Basic .NET에서는 <attribute>와 같이 꺾쇠괄호 안에 표시됨)을 사용하여 어셈블리, 응용 프로그램, 구성 요소 또는 메서드의 요소를 구성합니다. 예를 들어, 아래 코드에서는 SimpleTest 구성 요소에 트랜잭션이 필요하며, AddSale() 메서드가 오류 없이 완료될 경우 트랜잭션이 자동으로 완료된다는 것을 보여줍니다. C# [Transaction(TransactionOption.RequiresNew)] public class SimpleTest: ServicedComponent { ... [AutoComplete]public void AddSale(int orderNumber, int storeID, int titleID, int qty) { ... } ... } Visual Basic .NET<Transaction(TransactionOption.RequiresNew)> _Public Class VBTestObject : Inherits ServicedComponent ...<AutoComplete> _Public Function Sum(ByVal number1 As Integer, ByVal number2 As Integer) As Integer ... End Function ... End Class 다음 표에는 Enterprise Services 구성 요소에 적용할 수 있는 주로 사용되는 특성이 들어 있고, 설치 후에 특성을 안전하게 변경할 수 있는지 여부가 표시되어 있습니다. 위 표는 구성 요소 개발자가 기본적으로 소유하는 구성 요소와 관리자가 기본적으로 소유하는 구성 요소도 보여 줍니다. 코드에 미치는 영향을 자세히 알고 있는 경우가 아니라면 개발자의 설정을 변경하지 않는 것이 좋습니다. 개발자가 지정한 보안 관련 특성을 관리자가 변경할 수는 있지만, 이 경우에는 구성 요소 또는 응용 프로그램에 대한 액세스를 충분히 제한하되 너무 과도하게 제한하지는 않도록 주의를 기울여 보안을 구성해야 합니다. 특성을 통해 개발자는 자신의 구성 요소에 대한 구성 요구 사항을 간단하고 효율적으로 지정하면서 설치 후에 관리자가 구성 설정을 변경할 수 있도록 합니다. Enterprise Services가 제공하는 특성에 대한 자세한 내용은 .NET Framework Class Library 를 참조하십시오. .NET Enterprise Services와 COM+ 성능 비교Enterprise Services의 성능을 COM+와 비교하여 측정하기 위해 다음 언어로 구성 요소를 만들었습니다. - Visual C++ .NET 및 ATL COM+
- Visual Basic 6 COM+
- C# 및 .NET Framework 1.1 Enterprise Services
- Visual Basic .NET 및 .NET Framework 1.1 Enterprise Services
각 구성 요소에는 두 개의 공용 메서드가 포함되어 있습니다. - Sum(): 이 간단한 메서드는 두 숫자를 합해 디스크 또는 데이터베이스 액세스 작업을 수행하지 않는 간단한 작업을 시뮬레이트합니다.
- AddSale(): 이 일반적인 메서드는 트랜잭션되며, 테이블에 레코드를 삽입하고 반환 전에 트랜잭션을 완료하는 개인 메서드인 InsertSale()을 호출합니다. 이 메서드는 일반적인 비즈니스 응용 프로그램 작업을 수행하는 "실제" 메서드의 성능 특징을 보여 줍니다.
그 다음에는 각 구성 요소에 대해 다음 테스트를 수행한 테스트 프로그램을 만들었습니다. - 반복적인 만들기/호출/릴리스: 이 테스트는 개체를 만들고 호출하고 릴리스하는 과정을 반복적으로 수행합니다.
- 만들기/반복 호출/릴리스: 이 테스트는 개체를 인스턴스화하여 수천 번 호출한 다음 마지막에 개체를 릴리스합니다.
테스트 프로그램에서는 각 구성 요소에 대해 두 가지 테스트를 모두 실행했으며 결과를 쉼표로 분리된 파일에 작성하는 고해상도 타이머를 사용하여 각 테스트를 수행하는 데 걸린 시간을 측정했습니다. 이 파일의 결과를 Microsoft Excel로 가져와서 분석했습니다. 각 구성 요소에 대한 코드 목록은 부록 5: 성능 테스트 소스 코드를 참조하십시오. 테스트는 다음 표에 표시된 구성으로 설정된 컴퓨터에서 실행되었습니다. | 컴퓨터 1: 서버 컴퓨터 | 컴퓨터 2: 클라이언트 컴퓨터/단일 컴퓨터 |
---|
CPU | Dual Pentium 4 Xeon 3.06GHz | Dual Pentium 4 Xeon 2.8GHz | RAM | 1GB | 1GB | 디스크 | 로컬 SCSI | 로컬 SCSI | 네트워크 | 기가비트 이더넷 | 기가비트 이더넷 | OS 및 .NET | Windows Server™ 2003 .NET Framework 1.1 | Windows Server 2003 .NET Framework 1.1 |
다른 하드웨어에서 테스트 응용 프로그램을 실행할 때 나타나는 특정 결과는 아래에 보고된 결과는 물론, 서로 간에도 다를 수 있습니다. 그러나 각 결과는 여기에 소개된 결과와 비례해야 합니다. 테스트 결과 및 분석다음 절에서는 이전에 논의한 코드에 대해 실행한 성능 테스트의 결과를 분석합니다. 이 결과는 위에 나열된 하드웨어와 소프트웨어에서 테스트를 실행하여 얻은 것입니다. 모든 결과의 목록은 부록 6: 테스트 결과에 포함되어 있습니다. 결과를 보여 주는 다음 차트에서 차트 막대 길이가 길거나 숫자가 클수록 성능이 뛰어난 것입니다. 개체 활성화 및 삭제 성능먼저 C++ 및 Visual Basic 6을 사용하여 개발한 원시 COM+ 구성 요소의 성능을 통해 COM+ 인프라가 어떻게 수행되는지를 살펴보겠습니다. 아래 차트는 개체 만들기, 간단한 메서드 호출 및 개체 릴리스를 반복적으로 수행함으로써 얻은 초당 호출 수를 보여 줍니다. 
MTS(Microsoft Transaction Server) 1.0의 원래 디자이너는 이와 비슷한 데이터를 보고서 호출을 배달하는 데 필요한 인프라, 즉 프록시, DCOM(또는 프로세스간) 채널, 스텁 및 컨텍스트를 설정함으로써 프로세스 간 및 컴퓨터 간 활성화 시간에 큰 영향을 미칠 수 있다는 것을 깨달았습니다. 이 점이 다음을 수행하는 JIT(Just In Time) 활성화를 디자인하게 된 기본적인 동기였습니다. - 서버 구성 요소가 반환 이전에 SetComplete() 또는 SetAbort()를 호출하여 자체 수명 주기를 제어할 수 있도록 합니다.
- 여러 메서드 호출을 사용하여 DCOM 통로를 설정하는 부담을 줄입니다.
다음 차트는 JIT 활성화를 활용하는 수정된 테스트를 단일 개체를 만들고 두 숫자를 합하는 간단한 메서드를 반복적으로 호출한 다음 마지막에 개체를 릴리스하는 방법으로 실행할 경우 발생하는 상황을 보여 줍니다. 
이 결과는 JIT 활성화를 사용할 때 초당 호출 수 면에서 성능이 크게 향상되는 것을 보여 줍니다. JIT 활성화 및 Visual Basic 6을 사용하면 JIT 활성화를 사용하지 않는 C++보다 거의 33배 빠른 결과를 얻을 수 있습니다. JIT가 활성화된 Visual Basic 6에서는 초당 호출 수가 약 8600인 반면 JIT가 활성화되지 않은 Visual C++에서는 초당 호출 수가 약 261입니다. 작업을 수행하는 데 필요한 통로를 설정한 이후 컴퓨터 간 호출을 수행하면 네트워크가 성능에 큰 영향을 미치게 됩니다. 이 경우 Visual Basic 6 및 C++는 성능이 거의 비슷하지만, 그래도 Visual Basic 6가 C++보다 88% 빨리 수행됩니다. Enterprise Services에서는 필요한 통로를 설정하는 추가 작업이 수행됩니다. 특히 개체를 생성하고 릴리스하기 위한 추가 호출이 필요합니다. 따라서 개체에서 아무런 작업을 수행하지 않고 단순히 개체를 만들었다 제거하는 경우를 비교할 때 이러한 추가 왕복 부담이 성능 비교에 큰 영향을 미치게 됩니다. Visual Studio 2005에서는 Enterprise Services가 향상되어 이러한 활성화 왕복 중 하나가 제거되었기 때문에 "활성화/단일 호출/릴리스" 패턴을 사용할 때 .NET Framework 1.1과 비교하여 성능이 20-30% 향상됩니다. 그러나 가능하면 이러한 패턴은 사용하지 않는 것이 좋습니다. JIT 활성화를 사용할 때 C++ 및 Visual Basic 6의 성능이 비슷하다는 것을 고려하면 C# 및 Visual Basic .NET을 사용하는 Enterprise Services도 대략 같은 성능을 보일 것으로 예상할 수 있습니다. 아래 그림은 간단한 메서드를 호출하는 위 테스트를 실행한 결과를 보여 줍니다. 
이 데이터는 단순히 두 정수를 합하고, 개체의 컨텍스트에 SetComplete()를 호출하고, 결과를 반환하는 간단한 메서드에 대해 수행한 초당 호출 수를 보여 줍니다. 개체를 활성화하고 릴리스하는 부담은 거의 사라졌지만 버퍼를 마샬링하고 호출 스택으로 변환하는 등의 작업으로 인해 호출을 수행하는 부담은 아직 남아 있습니다. 이처럼 매우 간단한 메서드에서도 프로세스 간 호출의 경우 Enterprise Services는 Visual Basic 6과 성능이 거의 비슷합니다. 컴퓨터간에 호출할 경우에는 모든 언어의 성능이 거의 비슷합니다. 그러나 일반적인 비즈니스 응용 프로그램은 메서드에서 이보다 더 복잡한 작업을 수행합니다. 다음 차트는 일반적인 메서드를 호출하여 분산 트랜잭션 내에서 데이터베이스 연결을 열고 간단한 SQL 문을 실행하는 동일한 응용 프로그램을 네 가지 언어로 작성했을 때 각각의 상대적인 성능을 보여 줍니다. 
앞의 결과는 메서드 내에서 많은 작업을 수행할 경우 모든 언어의 결과가 실험 오차 범위 내에서 동등하다는 것을 보여 줍니다. ADO를 사용하는 C++ 및 Visual Basic 6을 통해 작성한 COM+ 원시 응용 프로그램은 Enterprise Services를 사용하는 C# 또는 Visual Basic .NET 응용 프로그램과 동일한 속도로 수행됩니다. 프로세스 간 작업을 실행하거나 컴퓨터 간 작업을 실행하는 경우 성능 면에서는 거의 차이가 없습니다. 결과 요약위 결과는 구성 요소를 최대한 효율적으로 수행하는 데 있어서 JIT 활성화 및 "만들기/반복 호출/릴리스" 패턴이 매우 중요하다는 것을 보여 줍니다. 결론코드를 .NET으로 마이그레이션하는 것이 유리한 몇 가지 주요 이유를 설명했습니다. 다른 활성화 및 호출 패턴에 적용될 때의 원시 COM+ 및 .NET Enterprise Services 구성 요소 성능에 대해서도 논의했습니다. 또한 지침을 따라가면서 .NET Enterprise Services 구성 요소가 C++ COM+ 구성 요소만큼 빨리 실행된다는 것을 보여 주었습니다. 부록 1: 성능 권장 사항에는 고성능 .NET Enterprise Service 구성 요소를 만드는 데 도움이 되는 주요 권장 사항이 나와 있습니다. 여기에 설명된 기술을 일관되게 적용하면 기존 COM+ 코드를 .NET Enterprise Service 구성 요소로 바로 변환하고 아무런 성능 저하 없이 .NET Framework의 사용성, 보안 및 개발자 생산성 등의 이점을 누릴 수 있습니다. 지금 COM+ 구성 요소를 Enterprise Services 구성 요소로 변환해 놓으면 나중에 코드를 "Indigo"로 더욱 쉽게 마이그레이션할 수 있다는 점도 중요합니다. 부록 2: "Indigo" 및 .NET의 동향에서는 이 주제에 대해 간략히 논의합니다. 부록 1: 성능 권장 사항다음 절에서는 높은 수준의 성능을 제공하는 빠른 COM+ 및 Enterprise Services 구성 요소를 만드는 방법에 대한 팁과 안내를 제공합니다. 대부분의 제안은 .NET Enterprise Services 구성 요소와 원시 COM+ 구성 요소에 동일하게 적용됩니다. 해당하는 경우 개체 풀링 및 JIT 활성화 사용위의 테스트 결과가 보여주듯이 메서드 호출이 구성 요소 활성화보다 빠르며 관리되지 않는 구성 요소의 활성화가 Enterprise Services 구성 요소의 활성화보다 빠릅니다. 따라서 구성 요소 기반 응용 프로그램의 속도를 최대한 높이려면 코드에서 구성 요소 활성화 및 삭제의 수를 최소화하는 것이 중요합니다. COM+에서는 개체 활성화를 최소화할 수 있는 두 가지 서비스를 제공합니다. - 첫 번째는 앞에서 설명했듯이 호출자가 개체에 대한 활성 참조를 보관하고 있는 동안 해당 개체를 원활하게 비활성화할 수 있는 COM+ 서비스인 JIT(Just-in-time) 활성화입니다. 클라이언트가 개체에 메서드를 호출하기만 하면 COM+가 개체의 할당을 동적으로 관리하여 요청을 처리합니다.
- 두 번째는 해당 형식의 구성 요소 인스턴스를 요청하는 클라이언트가 바로 사용할 수 있도록 개체를 풀에서 활성 상태로 유지하는 개체 풀링입니다. COM+는 풀을 자동으로 관리하며, 개체 활성화 정보를 처리하고 사용자가 지정한 기준(예: 풀 크기)에 따라 다시 사용합니다.
풀링된 구성 요소 및 JIT 활성화된 구성 요소에 대한 참조를 보관하고 다시 사용함으로써 구성 요소 활성화 및 삭제를 최소화하고 높은 수준의 성능을 얻을 수 있습니다. COM+ JIT 활성화 및 개체 풀링에 대한 자세한 내용은 Platform SDK: COM+ (Component Services) 설명서 를 참조하십시오. 왕복 회피COM+ 구성 요소의 성능을 최적화하려면 호출자와 구성 요소 사이에 수행되는 프로세스 간 또는 컴퓨터 간 호출의 수를 최소화하는 것이 중요합니다. COM+ 구성 요소에서 만들어진 모든 메서드는 프로세스 간 호출 전환은 물론 컴퓨터 간 호출 전환도 초래하며, 매번 전환할 때마다 시간이 걸립니다. 따라서 COM+ 개체에서 만들어지는 메서드 호출을 최소한으로 유지하는 것이 필수적입니다. 그러기 위해 단일 호출에서 최대한 많은 작업을 수행하는 메서드를 사용하여 COM+ 구성 요소를 디자인하는 것도 좋은 방법입니다. 단, 이 경우에는 순수 아키텍처에서 변형된 구성 요소도 디자인해야 합니다. COM+ 서비스 사용 최적화COM+가 중요한 서비스를 다수 제공하기는 하지만 이러한 서비스를 현명하게 사용하는 것이 중요합니다. COM+가 구성 요소에 필요한 서비스를 제공하는 경우에는 대개 이 서비스가 가장 높은 성능을 제공하므로 반드시 사용하도록 하십시오. 그러나 서비스가 필요하지 않은 경우에는 구성 요소가 불필요한 작업을 수행하여 실행 속도도 느려질 수 있으므로 해당 서비스를 사용할 필요가 없습니다. COM 마샬링 가능 매개 변수 사용호출자가 데이터를 전달할 때 사용하는 매개 변수를 Enterprise Services 구성 요소의 메서드가 받아들이는 경우 다음과 같이 COM과 .NET 사이에 쉽게 마샬링할 수 있는 형식을 사용할 것을 매우 강력히 제안합니다. - Boolean
- Byte, SByte
- Char
- DateTime
- Decimal
- Single, Double
- Guid
- Int16, UInt16, Int32, UInt32, Int64, UInt64
- IntPtr, UIntPtr
- String
이러한 형식만 사용하고 다른 복잡한 형식(예: 구조 또는 배열)은 전달하지 않으면 .NET serializer가 호출 처리 스택을 최적화하고 호출을 유선(RPC의 경우) 또는 가상 유선(LRPC의 경우)에 일렬로 직렬화할 수 있습니다. 그러면 호출이 더욱 빨리 실행됩니다. 그러나 메서드에 복잡한 형식이 필요한 경우에는 코드가 일반 DCOM 호출 스택을 통해 호출되므로 추가 처리 과정이 발생합니다. 파이널라이저 사용하지 않기Enterprise Services 구성 요소에서 파이널라이저(C# 및 C++의 ~Classname() 소멸자)를 구현하지 마십시오. 파이널라이제이션은 가비지 수집기의 단일 스레드 작업입니다. Enterprise 구성 요소를 파이널라이제이션할 경우 완료되는 데 상당한 시간이 걸리므로 가비지 수집기 성능이 저하됩니다. 가비지 수집기 엔진이 실행 중인 동안에는 응용 프로그램에서 다른 작업을 수행할 수 없으므로 가비지 수집기가 완료되는 데 오랜 시간이 걸리면 전체 응용 프로그램의 성능이 저하됩니다. 대신 개체에서 Dispose(bool)을 재정의하고 Dispose(true)가 호출될 때 파이널라이제이션 형식 작업을 수행하는 것을 고려해 보십시오. 또한 이러한 종료 코드를 최대한 정돈되고, 안전하고, 간단하게 유지하도록 하십시오. 단일 스레드 COM+ 구성 요소 만들지 않기여러 스레드의 동시 액세스를 지원하지 않는 개체는 STA(단일 스레드 아파트) 기능을 지원하는 것으로 표시되어 있습니다. 여러 스레드가 같은 인스턴스에 동시 액세스할 수 있도록 지원하는 구성 요소는 MTA(다중 스레드 아파트) 인식으로 표시되어 있습니다. .NET Enterprise Services 구성 요소는 항상 STA 및 MTA를 모두 지원하는 것으로 표시되어 있기 때문에 더 이상 이 논의에 포함시키지 않겠습니다. 모든 Visual Basic 6 COM+ 구성 요소는 STA입니다. C++ COM+ 개발자는 구성 요소를 STA, MTA 또는 둘 다로 표시할 수 있습니다. STA COM+ 구성 요소의 잠재적인 문제는 개체가 단일 스레드에서만 실행될 수 있으므로 해당 스레드가 개체의 메서드를 실행하는 유일한 스레드라는 것입니다. 이 직렬화를 통해 개발자는 STA 구성 요소를 더욱 쉽게 작성할 수 있지만, 도메인 간 마샬링이 종종 필요해서 성능이 저하되고 STA에서 한 스레드만 계속 실행됨으로 인해 확장성이 떨어지는 것은 피할 수 없습니다. 가능하면 STA 구성 요소를 만들거나 사용하지 않을 것을 제안합니다. 특히 확장성이 중요한 곳에서는 더욱 그렇습니다. 구성 요소가 다른 COM+ 구성 요소를 호출하는 경우 특히 STA 스레딩을 피해야 합니다. 이러한 호출에는 종종 스레드 전환이 필요한데, 스레드 전환은 해당 아파트에 있는 다른 모든 COM+ 구성 요소를 차단합니다. 설상가상으로 가비지 수집기의 파이널라이저도 개체를 소유한 STA 스레드를 호출할 때 차단됩니다. 그러면 파이널라이제이션 프로세스가 단일 스레드에 직렬화되며, 이는 이전 주제에서 설명했듯이 시스템 성능을 크게 저하시킬 수 있습니다. 부록 2: "Indigo" 및 .NET의 동향Microsoft에서 현재 개발 중인 연결된 응용 프로그램을 위한 새로운 플랫폼, 코드 이름 "Indigo"에 대해 들어 보셨을 것입니다. 그렇다면 "Indigo"란 과연 어떤 제품일까요? "Indigo"는 서비스 지향 연결 응용 프로그램을 위한 Microsoft의 전략적 기술 플랫폼으로서, 로스앤젤레스에서 개최된 2003 PDC(Professional Developers Conference)에서 소개되었습니다. "Indigo"는 다음 기술의 개념, 특징 및 기능을 하나의 기술 스택으로 통합합니다. - COM
- DCOM
- COM+/Enterprise Services
- ASMX/Web Services
- .NET Remoting
- 향상된 웹 서비스
- MSMQ의 요소
"Indigo"는 서비스를 호출자에게 노출하는 데 필요한 프로토콜 및 전송으로부터 서비스의 개념을 추상화하는 다계층 플랫폼입니다. 최대한 많은 시스템과 상호 작동하기 위해 "Indigo"는 HTTP, TCP 및 IPC를 통한 고급 웹 서비스(WS-*)를 완벽하게 지원합니다. 현재 Microsoft는 코드 이름이 "Longhorn"인 Microsoft Windows의 출시 시기에 맞춰 "Indigo"를 배포할 예정입니다. Windows XP 및 Windows Server 2003에 대한 "Indigo" 지원도 함께 배포될 것입니다. 향후 "Indigo"가 발표된다고 하니 .NET Enterprise Services(또는 이 경우 ASMX 및 Remoting) 같은 기존 기술이 오늘날의 연결된 응용 프로그램을 개발하는 데 아직 유효한 것인지 걱정할 수도 있습니다. ASMX & WSE, Enterprise Services, Remoting 및 MSMQ는 오늘날의 엔터프라이즈 수준 솔루션에 가장 적합한 기술입니다. 적절하게 사용하면 "Indigo"가 릴리스되고 널리 사용될 때까지 훌륭한 응용 프로그램 개발 플랫폼을 제공해 줄 것입니다. .NET을 사용하여 새 응용 프로그램을 작성하고 기존 응용 프로그램을 .NET으로 마이그레이션하면 향상된 보안, 안정성, 관리 및 확장성의 혜택을 누릴 수 있습니다. 또한 "Indigo"로 업그레이드하는 것이 원시 코드보다 훨씬 쉬워질 것입니다. 응용 프로그램의 "Indigo" 업그레이드를 준비하는 방법과 기존 기술을 사용하여 "Indigo"와 상호 작동하는 방법에 대한 자세한 내용은 나중에 MSDN을 참조하십시오. "Indigo"에 대한 자세한 소개는 MSDN Magazine 기사, Code Name Indigo: A Guide to Developing and Running Connected Systems with Indigo 를 참조하십시오. 이 기사에 제공된 아키텍처 개요를 통해 이후의 Microsoft 응용 프로그램 플랫폼을 미리 살펴볼 수 있습니다. "Indigo"에 대한 일반적인 내용은 Microsoft "Indigo" Frequently Asked Questions 를 참조하십시오. 부록 3: 분산 트랜잭션이 성능에 미치는 영향위 테스트를 진행하면서 "COM+ 분산 트랜잭션이 이러한 구성 요소에 얼마나 많은 영향을 미칠까?"라는 질문이 생길 수도 있습니다. 이 질문의 답을 찾기 위해 각 구성 요소에 대해 COM+에서 "트랜잭션 필요" 설정을 끄고 테스트를 다시 실행해 보았습니다. 그 결과는 다음 차트에 표시되어 있습니다. 
위 차트에서 볼 수 있듯이 COM+ 트랜잭션 지원이 없는 구성 요소의 성능과 트랜잭션이 켜져 있는 구성 요소의 성능은 거의 동일합니다. 이 결과는 테스트에서 COM+ 트랜잭션의 영향을 무시해도 상관없다는 것을 분명하게 보여 줍니다. 부록 4: 참고 자료Upgrading Microsoft Visual Basic 6.0 to Microsoft Visual Basic .NET  Visual Basic 6.0 응용 프로그램을 Visual Basic .NET으로 업그레이드하는 내용을 다루며 프로그래밍 팁, 요령 및 단계별 코드 비교 내용을 함께 제공합니다. Programming with Managed Extensions for Microsoft Visual C++ .NET  Visual C++ .NET 2003에 맞춰 업데이트된 이 책은 개발자를 위해 컴파일러의 새 기능과 언어에 대한 링커 확장을 심층적이고 전문적으로 다룹니다. .NET Enterprise Services and COM+ 1.5 Architecture  Microsoft .NET 및 Enterprise Services가 어떻게 조화를 이루는지 보여 주고 COM+/Enterprise Services 구성 요소를 빌드, 제어, 관리 및 보안하는 방법을 설명합니다. .NET Framework Developer Center의 Performance 페이지  고성능 코드를 작성하는 방법과 발생하는 문제를 진단하는 방법에 대해 심도있게 다루는 여러 링크와 리소스가 제공됩니다. Performance Tips and Tricks in .NET Applications  .NET 응용 프로그램이 제대로 수행되도록 하기 위한 팁과 힌트를 모아 놓았습니다. Writing Faster Managed Code: Know What Things Cost  .NET 코드에서 다양한 작업이 시스템에 어떤 부담을 주는지 자세히 분석한 내용입니다. Garbage Collector Basics and Performance Hints  가비지 수집기의 작동 방법, 가비지 수집기가 코드에 미치는 영향, 가비지 수집의 영향을 최소화하도록 코드를 작성하는 방법 등에 대해 설명합니다. Performance Considerations for Run-Time Technologies in the .NET Framework  가비지 수집 및 메모리 사용, JIT, 스레딩, .NET Remoting, 보안 등의 주제를 다룹니다.
|