Have the application access server objects in the same order each time.

During transactions, don’t allow any user input. Collect it before the transaction begins.

Avoid cursors.

Keep transactions as short as possible. One way to help accomplish this is to reduce the number of round trips between your application and SQL Server by using stored procedures or keeping transactions with a single batch. Another way of reducing the time a transaction takes to complete is to make sure you are not performing the same reads over and over again. If you do need to read the same data more than once, cache it by storing it in a variable or an array, and then re-reading it from there.

Reduce lock time. Try to develop your application so that it grabs locks at the latest possible time, and then releases them at the very earliest time.

If appropriate, reduce lock escalation by using the ROWLOCK or PAGLOCK.

Consider using the NOLOCK hint to prevent locking if the data being locked is not modified often.

If appropriate, use as low of an isolation level as possible for the user connection running the transaction.

Consider using bound connections.

However, deadlock still occurs sometimes.So we have to deal with it by re-submit the transaction again. See below sample:

I just finished writing my first production WCF application, which worked very well until I deployed it to our production environment. All of a sudden none of the WCF calls would work, and I would get a JavaScript “TestService is not defined” error. When I look inside the JS service reference (in debug mode), I got the following error:

Could not find a base address that matches scheme http for the endpoint with binding WebHttpBinding. Registered base address schemes are [https]

So apparently my WCF service registered itself as HTTPS (since it is over SSL), but my binding was only configured for HTTP. The solution is to define a custom binding inside your Web.Config file and set the security mode to “Transport”. Then you just need to use the bindingConfiguration property inside your endpoint definition to point to your custom binding. The entire HTTPS-enabled system.serviceModel section is below:

I often have to remind the dedicated, smart CEOs I work with that leading takes time and energy. Directing the feelings, attitudes, actions, and behaviors of a team is a big task. Often, I also hear the secrets of these CEOs’ employees, about what truly aggravates them and what they love about their bosses. To keep top executives on track, I’ve created this list of what employees want their leaders to do.

1. Tell me my role, tell me what to do, and give me the rules. Micromanaging? No, it’s called clear direction. Give them parameters so they can work within broad outlines.

2. Discipline my coworker who is out of line. Time and time again, I hear, “I wish my boss would tell Nancy that this is just unacceptable.” Hold people accountable in a way that is fair but makes everyone cognizant of what is and isn’t acceptable.

3. Get me excited. About the company, about the product, about the job, about a project. Just get them excited.

4. Don’t forget to praise me. Motivate employees by leveraging their strengths, not harping on their weaknesses.

5. Don’t scare me. They really don’t need to know about everything that worries you. They respect that you trust them, but you are the boss. And don’t lose your temper at meetings because they didn’t meet your expectations. It’s often not productive. Fairness and consistency are important mainstays.

6. Impress me. Strong leaders impress their staffs in a variety of ways. Yes, some are great examples of management, but others are bold and courageous, and still others are creative and smart. Strong leaders bring strength to an organization by providing a characteristic that others don’t have and the company sorely needs.

7. Give me some autonomy. Give them something interesting to work on. Trust them with opportunity.

8. Set me up to win. Nobody wants to fail. Indecisive leaders who keep people in the wrong roles, set unrealistic goals, keep unproductive team members, or change direction unfairly just frustrate everybody and make people feel defeated.

Your job is to make it practical for people to succeed. When you do this, everybody wins.

Programmers love to work long hours! There I said it, c’mon admit it, your job/boss doesn’t make you do it, we do it to ourselves. Alright, I’ll concede, maybe not all programmers love long hours, but surely with the amount of overtime that is prevalent in this industry at least half of us must love it. Right?

I can hear the excuses already. “No, no that’s not it, we just love working with cool tech and don’t want to leave a problem unsolved. It is actually a good thing it’s what makes us awesome!“

I say – you’re not seeing the forest for the trees. Here is some perspective, you’re not doing this for yourself, you’re doing it for “the man“. Admittedly he might be a nice man, but you don’t owe him slavish commitment. Here is even more perspective, how often are you actually playing with interesting problems and cool tech and how many times are you churning out code desperately trying to get something delivered and meet some arbitrary deadline that someone has assigned to you? But hey, you’re a business savvy developer, you’re helping the company succeed, your manager has explained the financial situation to you – it has to be done, we’re relying on you. Well, unless that same manager is right there with you, entertaining you with amusing anecdotes at 2 am, his words are worthless.

Let me tell you a story that a friend once told me. It is about a brilliant developer – lets call him John.

John was a superstar, a one in a million programmer. He had an uncanny ability to understand and write code and was 20 times more productive than anyone else. One day the company got a big contract that needed a fast turn-around. The client sent a massive spec document – to everyone’s dismay. John came to the rescue, he took the spec home and noone heard from him for 3 days. When he came back to work, he looked like hell, but he had gone through the whole spec and had an outline of the solution already finished. Except for one bit which was impossible to implement, though the spec said otherwise – even the client didn’t realise this, but John picked it up. Amazing!

When I first heard that story, I was pretty impressed, my first question was, “So, where is this guy now?“. To which my friend replied – “He is dead, too much hard living!“. Too much hard coding would be more like it. Kinda takes the wind out of that story a little bit – John was in his early 30s.

Programmers take a perverse pleasure from sharing death-march war stories. Even when we do it with disgust, it is a disgust tinged with pride – daring our peers to do “better“. But it is a bit like those guys who wear their pants so low you can see ALL of their underwear or the people who take up smoking for the “trendy image“. They and their friends think it’s cool – everybody else thinks it’s stupid.

Making A Bad Situation Worse

I can see the necessity of occasionally putting in some extra effort and burning the midnight oil at work for a day or two. But when “occasionally” turns to “often“, when your boss stops thanking you profusely for your efforts and just treats it as norm, this is when we’re all in trouble. It sets bad expectations, not just for you, for the whole industry. Humans are like dogs, we’re eminently susceptible to positive and negative reinforcement. And this whole industry has been conditioned by years of death-marches to the point where it even rewards this behaviour. Every time we give-in to the long hours argument, we continue to negatively reinforce this trend.

It doesn’t help that we’re herd animals, you only need to get one person and everyone else wants to conform. Guilt comes into the equation – “we can’t leave our mates by themselves to do the hard-yards, we gotta help them“. The more people conform, the more pressure on the rest of the herd to do so until the whole team is chugging coke and eating pizza at midnight. But how do they suck even one person in, where is that famed programmer independence. We’re happy to “stick it to the man” and do whatever we want in school, but as soon as we’re in the workforce all bets are off. It is puzzling.

Interestingly, sometimes these gargantuan efforts aren’t even tracked properly, as it would make the project look bad. So they “cook the books“, as far as the client is concerned everybody is doing 40 hours a week (i.e. they get billed for 40 hours) and the project is coming in on schedule (maybe), never mind the other 40 hours that everyone on the team puts in. OK, maybe they’ll track the real effort in a “second set of books“. Accountants go to jail for these kinds of shenanigans, but our industry expects it – nay almost demands it.

The Sustainable Pace Effort

Most Agile processes talk about sustainable development pace. But, I’ve seen even self-confessed agile teams knuckle under and put in the hours, you know, for the greater good and all. They were still agile though, and don’t you dare say otherwise.

When I think about this stuff I am always reminded of lawyers. You come in as a new lawyer and you put in massive amounts of effort and time, it is the accepted way to get ahead in that industry. No developer wants to be compared to lawyers, but often the situation is similar except you’re not going to get ahead by doing a lot of overtime as a developer (unless you’re working for a big 4 consulting company and then you might as well be a lawyer :)). So, lawyer vs programmer, which one is the chump?

Studies about productivity declines when working more than 40 hours a week surface with disturbing regularity. As a developer your creativity declines, you make more mistakes, you miss existing issue etc., to the point where you’re doing more harm than good. Should I even mention the health concerns when you spend that much time engaged in the same activity (they even had rules about spending too much time at work in the Soviet Union, and those guys were all about putting in the time for the good of the people). What about diet, you can only survive on coke for so long – poor John couldn’t even make it to 40.

Can you tell that I am against long hours and death marches yet :)? Maybe one of these days I’ll tell you how I got my wake-up call, it is an interesting story. Herding cats is easy compared to getting developers to make a concerted effort in the same direction, it is something I both love and hate about our people (programmers) :). But I do wish that once in a while all the smart developers just took a stand to eliminate at least one of the truly crappy and counter-productive trends in our industry. As far as I am concerned, smart programmers don’t like to work long hours and won’t be pressured into it – there is more to life.

Applies To

ASP.NET version 1.1

ASP.NET version 2.0

Summary

This How To shows how you can help protect your ASP.NET applications from cross-site scripting attacks by using proper input validation techniques and by encoding the output. It also describes a number of other protection mechanisms that you can use in addition to these two main countermeasures.Cross-site scripting (XSS) attacks exploit vulnerabilities in Web page validation by injecting client-side script code. Common vulnerabilities that make your Web applications susceptible to cross-site scripting attacks include failing to properly validate input, failing to encode output, and trusting the data retrieved from a shared database. To protect your application against cross-site scripting attacks, assume that all input is malicious. Constrain and validate all input. Encode all output that could, potentially, include HTML characters. This includes data read from files and databases.

Overview

Cross-site scripting attacks exploit vulnerabilities in Web page validation by injecting client-side script code. The script code embeds itself in response data, which is sent back to an unsuspecting user. The user’s browser then runs the script code. Because the browser downloads the script code from a trusted site, the browser has no way of recognizing that the code is not legitimate, and Microsoft Internet Explorer security zones provide no defense. Cross-site scripting attacks also work over HTTP and HTTPS (SSL) connections. One of the most serious examples of a cross-site scripting attack occurs when an attacker writes script to retrieve the authentication cookie that provides access to a trusted site and then posts the cookie to a Web address known to the attacker. This enables the attacker to spoof the legitimate user’s identity and gain illicit access to the Web site.Common vulnerabilities that make your Web application susceptible to cross-site scripting attacks include:

Failing to constrain and validate input.

Failing to encode output.

Trusting data retrieved from a shared database.

Guidelines

The two most important countermeasures to prevent cross-site scripting attacks are to:

Constrain input.

Encode output.

Constrain Input

Start by assuming that all input is malicious. Validate input type, length, format, and range.

To constrain input supplied through server controls, use ASP.NET validator controls such as RegularExpressionValidator and RangeValidator.

To constrain input supplied through client-side HTML input controls or input from other sources such as query strings or cookies, use the System.Text.RegularExpressions.Regex class in your server-side code to check for expected using regular expressions.

To validate types such as integers, doubles, dates, and currency amounts, convert the input data to the equivalent .NET Framework data type and handle any resulting conversion errors.

Encode Output

Use the HttpUtility.HtmlEncode method to encode output if it contains input from the user or from other sources such as databases. HtmlEncode replaces characters that have special meaning in HTML-to-HTML variables that represent those characters. For example, < is replaced with < and “ is replaced with “. Encoded data does not cause the browser to execute code. Instead, the data is rendered as harmless HTML.Similarly, use HttpUtility.UrlEncode to encode output URLs if they are constructed from input.

Summary of Steps

To prevent cross-site scripting, perform the following steps:

Step 1. Check that ASP.NET request validation is enabled.

Step 2. Review ASP.NET code that generates HTML output.

Step 3. Determine whether HTML output includes input parameters.

Step 4. Review potentially dangerous HTML tags and attributes.

Step 5. Evaluate countermeasures.

Step 1. Check That ASP.NET Request Validation Is Enabled

By default, request validation is enabled in Machine.config. Verify that request validation is currently enabled in your server’s Machine.config file and that your application does not override this setting in its Web.config file. Check that validateRequest is set to true as shown in the following code example.

You can disable request validation on a page-by-page basis. Check that your pages do not disable this feature unless necessary. For example, you may need to disable this feature for a page if it contains a free-format, rich-text entry field designed to accept a range of HTML characters as input. For more information about how to safely handle this type of page, see Step 5. Evaluate Countermeasures.To test that ASP.NET request validation is enabled

Create an ASP.NET page that disables request validation. To do this, set ValidateRequest=”false”, as shown in the following code example.

<%@ Page Language="C#" ValidateRequest="false" %>

void btnSubmit_Click(Object sender, EventArgs e){// If ValidateRequest is false, then 'hello' is displayed// If ValidateRequest is true, then ASP.NET returns an exceptionResponse.Write(txtString.Text);}

Text="<script>alert('hello');</script>" />

OnClick="btnSubmit_Click" Text="Submit" />

Run the page. It displays Hello in a message box because the script in txtString is passed through and rendered as client-side script in your browser.

Set ValidateRequest=”true” or remove the ValidateRequest page attribute and browse to the page again. Verify that the following error message is displayed.

A potentially dangerous Request.Form value was detected from the client (txtString="alert('hello...").

This indicates that ASP.NET request validation is active and hasrejected the input because it includes potentially dangerous HTMLcharacters.

Note Do not rely on ASP.NET request validation.Treat it as an extra precautionary measure in addition to your owninput validation.

Step 2. Review ASP.NET Code That Generates HTML Output

ASP.NET writes HTML as output in two ways, as shown in the following code examples.

Response.Write<% =

Search your pages to locate where HTML and URL output is returned to the client.

Step 3. Determine Whether HTML Output Includes Input Parameters

Analyze your design and your page code to determine whether theoutput includes any input parameters. These parameters can come from avariety of sources. The following list includes common input sources:

Be particularly careful with data read from a database if it is shared by other applications.

Cookie collection, such as the following:

Response.Write(Request.Cookies["name"].Values["name"]);

Session and application variables, such as the following:

Response.Write(Session["name"]);Response.Write(Application["name"]);

In addition to source code analysis, you can also perform a simple test by typing text such as “XYZ” in form fields and testing the output. If the browser displays “XYZ” or if you see “XYZ” when you view the source of the HTML, your Web application is vulnerable to cross-site scripting.

To see something more dynamic, inject <script>alert(‘hello’);</script>through an input field. This technique might not work in all casesbecause it depends on how the input is used to generate the output.

Step 4. Review Potentially Dangerous HTML Tags and Attributes

If you dynamically create HTML tags and construct tag attributeswith potentially unsafe input, make sure you HTML-encode the tagattributes before writing them out.

The following .aspx page shows how you can write HTML directly to the return page by using the <asp:Literal>control. The code takes user input of a color name, inserts it into theHTML sent back, and displays text in the color entered. The page uses HtmlEncode to ensure the inserted text is safe.

Potentially Dangerous HTML Tags

While not an exhaustive list, the following commonly used HTML tags could allow a malicious user to inject script code:

<applet>

<body>

<embed>

<frame>

<script>

<frameset>

<html>

<iframe>

<img>

<style>

<layer>

<link>

<ilayer>

<meta>

<object>

An attacker can use HTML attributes such as src, lowsrc, style, and href in conjunction with the preceding tags to inject cross-site scripting. For example, the src attribute of the <img> tag can be a source of injection, as shown in the following examples.

An attacker can also use the <style> tag to inject a script by changing the MIME type as shown in the following.

alert('hello');

Step 5. Evaluate Countermeasures

When you find ASP.NET code that generates HTML using some input, you need to evaluate appropriate countermeasures for your specific application. Countermeasures include:

Encode HTML output.

Encode URL output.

Filter user input.

Encode HTML Output

If you write text output to a Web page and you do not know if the text contains HTML special characters (such as <, >, and &), pre-process the text by using the HttpUtility.HtmlEncode method as shown in the following code example. Do this if the text came from user input, a database, or a local file.

Response.Write(HttpUtility.HtmlEncode(Request.Form["name"]));

Do not substitute encoding output for checking that input is well-formed and correct. Use it as an additional security precaution.

Encode URL Output

If you return URL strings that contain input to the client, use the HttpUtility.UrlEncode method to encode these URL strings as shown in the following code example.

Response.Write(HttpUtility.UrlEncode(urlString));

Filter User Input

If you have pages that need to accept a range of HTML elements, for example through some kind of rich text input field, you must disable ASP.NET request validation for the page. If you have several pages that do this, create a filter that allows only the HTML elements that you want to accept. A common practice is to restrict formatting to safe HTML elements such as bold (<b>) and italic (<i>).To safely allow restricted HTML input

Disable ASP.NET request validation by the adding the ValidateRequest=”false” attribute to the @ Page directive.

Encode the string input with the HtmlEncode method.

Use a StringBuilder and call its Replace method to selectively remove the encoding on the HTML elements that you want to permit.

The following .aspx page code shows this approach. The page disables ASP.NET request validation by setting ValidateRequest=”false”. It HTML-encodes the input and then selectively allows the <b> and <i> HTML elements to support simple text formatting.

Additional Considerations

In addition to the techniques discussed previously in this How To, use the following countermeasures as further safe guards to prevent cross-site scripting:

Set the correct character encoding.

Do not rely on input sanitization.

Use the HttpOnly cookie option.

Use the <frame> security attribute.

Use the innerText property instead of innerHTML.

Set the Correct Character Encoding

To successfully restrict valid data for your Web pages, you should limit the ways in which the input data can be represented. This prevents malicious users from using canonicalization and multi-byte escape sequences to trick your input validation routines. A multi-byte escape sequence attack is a subtle manipulation that uses the fact that character encodings, such as uniform translation format-8 (UTF-8), use multi-byte sequences to represent non-ASCII characters. Some byte sequences are not legitimate UTF-8, but they may be accepted by some UTF-8 decoders, thus providing an exploitable security hole.ASP.NET allows you to specify the character set at the page level or at the application level by using the <globalization> element in the Web.config file. The following code examples show both approaches and use the ISO-8859-1 character encoding, which is the default in early versions of HTML and HTTP.To set the character encoding at the page level, use the <meta> element or the ResponseEncoding page-level attribute as follows:

content="text/html; charset=ISO-8859-1" />

OR<% @ Page ResponseEncoding="iso-8859-1" %>

To set the character encoding in the Web.config file, use the following configuration.

requestEncoding="iso-8859-1" responseEncoding="iso-8859-1"/>

Validating Unicode Characters

Use the following code to validate Unicode characters in a page.

using System.Text.RegularExpressions;. . .

public class WebForm1 : System.Web.UI.Page{ private void Page_Load(object sender, System.EventArgs e) { // Name must contain between 1 and 40 alphanumeric characters // and (optionally) special characters such as apostrophes // for names such as O'Dell

if (!Regex.IsMatch(Request.Form["name"], @"^[\p{L}\p{Zs}\p{Lu}\p{Ll}\']{1,40}$")) throw new ArgumentException("Invalid name parameter");

The following explains the regular expression shown in the preceding code:

^ means start looking at this position.

\p{ ..} matches any character in the named character class specified by {..}.

{L} performs a left-to-right match.

{Lu} performs a match of uppercase.

{Ll} performs a match of lowercase.

{Zs} matches separator and space.

‘matches apostrophe.

{1,40} specifies the number of characters: no less than 1 and no more than 40.

$ means stop looking at this position.

Do Not Rely on Input Sanitization

A common practice is for code to attempt to sanitize input by filtering out known unsafe characters. Do not rely on this approach because malicious users can usually find an alternative means of bypassing your validation. Instead, your code should check for known secure, safe input. Table 1 shows various safe ways to represent some common characters.

Table 1: Character Representation

Characters

Decimal

Hexadecimal

HTML Character Set

Unicode

” (double quotation marks)

&#34

&#x22

“

\u0022

‘ (single quotation mark)

&#39

&#x27

‘

\u0027

& (ampersand)

&#38

&#x26

&

\u0026

< (less than)

&#60

&#x3C

<

\u003c

> (greater than)

&#62

&#x3E

>

\u003e

Use the HttpOnly Cookie Option

Internet Explorer 6 Service Pack 1 and later supports an HttpOnly cookie attribute, which prevents client-side scripts from accessing a cookie from the document.cookie property. Instead, the script returns an empty string. The cookie is still sent to the server whenever the user browses to a Web site in the current domain.

Note Web browsers that do not support the HttpOnly cookie attribute either ignore the cookie or ignore the attribute, which means that it is still subject to cross-site scripting attacks.

The System.Net.Cookie class in Microsoft .NET Framework version 2.0 supports an HttpOnly property. The HttpOnly property is always set to true by Forms authentication. Earlier versions of the .NET Framework (versions 1.0 and 1.1) require that you add code similar to the following to the Application_EndRequest event handler in your application Global.asax file to explicitly set the HttpOnly attribute.

protected void Application_EndRequest(Object sender, EventArgs e) { string authCookie = FormsAuthentication.FormsCookieName; foreach (string sCookie in Response.Cookies) { // Just set the HttpOnly attribute on the Forms // authentication cookie. Skip this check to set the attribute // on all cookies in the collection

Use the Security Attribute

Internet Explorer 6 and later support a new security attribute for the <frame> and <iframe> elements. You can use the security attribute to apply the user’s Restricted Sites Internet Explorer security zone settings to an individual frame or iframe. By default, the Restricted Sites zone does not support script execution. If you use the security attribute, it must be set to “restricted” as shown in the following.

Use the innerText Property Instead of innerHTML

If you use the innerHTML property to build a page and the HTML is based on potentially untrusted input, you must use HtmlEncode to make it safe. To avoid having to remember to do this, use innerText instead. The innerText property renders content safe and ensures that scripts are not executed.The following example shows this approach for two HTML <span> controls. The code in the Page_Load method sets the text displayed in the Welcome1 <span> element using the innerText property, so HTML-encoding is unnecessary. The code sets the text in the Welcome2 <span> element by using the innerHtml property; therefore, you must HtmlEncode it first to make it safe.

Additional Resources

]]>https://truongquangbinh.wordpress.com/2010/02/25/how-to-prevent-cross-site-scripting-in-asp-net/feed/0tubewar>COM Interop Exposedhttps://truongquangbinh.wordpress.com/2010/02/23/com-interop-exposed/
https://truongquangbinh.wordpress.com/2010/02/23/com-interop-exposed/#respondTue, 23 Feb 2010 08:19:00 +0000http://truongquangbinh.wordpress.com/2010/02/23/com-interop-exposedContinue reading →]]>>Introduction Microsoft realized that the very first version of .NET needed a way to work with the existing Windows technology used to develop applications over the past 8+ years: COM. With that in mind, Microsoft added support in the .NET runtime for interoperating with COM – simply called “COM Interop”. The support goes both ways: .NET code can call COM components and COM code can call .NET components. This article is geared towards VB6 programmers who are familiar with developing COM components and familiar with the concept of an interface. I’ll review some background on COM, explain how VB6 interacts with COM, and then show how to design .NET components to smoothly interact with COM. In a future article, I’ll discuss how to use an existing COM component in .NET applications. For those die-hard COM experts, there will be some things in this article that are oversimplified, but the concepts, as presented, are the important points to know for those developers supplementing their COM code with .NET components.

A Brief History of COM and VB6 One of the key concepts of COM is that everything is called through an interface. There is no such thing as simply creating a COM object and calling a method. You must use an interface. You’re probably thinking “Wait a minute! I’ve coded hundreds of classes in VB6 and never needed an interface”. That’s right – you didn’t need one because VB6 provided it for you in the background. Whenever you defined a public method on a class, VB6 made that method part of a COM interface and made your class implement the interface. For example, consider the following VB6 class from an ActiveX DLL project. The class is called “Robot”:

Option Strict

Public Sub MoveForward() ...End Sub

Public Sub FindCar() ...End Sub

When you compile this into a DLL, VB6 creates an interface called “_Robot” (note the leading underscore) and a “coclass” called “Robot”, which implements the interface “_Robot” (a “coclass” is the actual COM creatable object). The Microsoft utility OLE View is a tool used to examine the types defined in a COM component. OLE View should be installed under “Start, Programs, Microsoft Visual Studio 6.0, Microsoft Visual Studio 6.0 Tools, OLE View”. Using the ActiveX DLL compiled above, I started up OLE View, selected “View TypeLib…” from the “File” menu and selected the DLL. Here are the important parts of the output:

The first item to point out is that there is an interface called “_Robot”. This is the interface VB6 creates for us. It defines the two methods I added to the class (MoveForward and FindCar). Next, you’ll see a “coclass” called “Robot”. This represents the actual, creatable class. Since everything in COM is called through an interface, the “coclass” lists all interfaces supported by this object. Right now, there is only the “_Robot” interface – and it’s marked with the “default” modifier. There are a lot of COM details about the default interface, but for this article, the importance of a default interface in terms of VB6 components is that of all the interfaces a class may implement, only the default interface supports late binding. And since scripting clients like VBScript only do late binding, the methods on the default interface are the only ones they can see.

Multiple Interfaces COM will allow you to implement more than one interface. Take the ActiveX DLL from the previous section and add a new class module called “IMaid” (VB6 doesn’t support directly creating a COM interface – more on that below). Here’s the IMaid code:

Option Explicit

Public Sub CleanKitchen() ...End Sub

Public Sub WashCar() ...End Sub

Now add “Implements IMaid” to the Robot class:

Option Explicit

Implements IMaid

Public Sub MoveForward()End Sub

Public Sub FindCar()End Sub

Private Sub IMaid_CleanKitchen()End Sub

Private Sub IMaid_WashCar()End Sub

If I compile this DLL now and examine it with OLE View, I see the following structures (again, only the relevant portions are shown below):

As noted earlier, VB6 does not support creating a true COM interface. However, since VB6 creates a COM interface with every class (prefixed with the underscore), the VB6 compiler will actually use the auto-generated interface when compiling the code when you use the “Implements” keyword on a class in VB6. So above, the Robot coclass implements the interface _Robot (automatically generated by VB6) and the _IMaid interface (the automatically generated one from the IMaid class). Also note that the _Robot interface created by VB6 is marked as the default interface. If you were going to use this object in a scripting environment (such as an ASP page), you could only access the MoveForward and FindCar methods. The methods implemented by the IMaid interface are not accessible since they are not on the default interface. Almost to .NET! If you’ve stuck around this long, the answer is yes, you’re getting close to some .NET code! But it’s important to know these concepts before you move into making .NET components that you expose to COM. Think of it as having a blueprint before starting to build a house. Sure, you can work without a blueprint, but the house will come out much nicer if you start off right. A quick recap of what happens in VB6 when it creates COM objects:

COM is interface based. Everything in COM must be called through an interface.

VB6 doesn’t require that you implement a specific interface when creating a COM class. Instead, it will create an interface for you. Its name will be defined as your class name prefixed with the underscore (_) character.

The interface created by VB6 is always marked as the default COM interface and therefore only those methods are available to scripting clients (in the example above, VBScript can not access the IMaid methods of the Robot object).

Where Are My Methods?! Many people who first expose a .NET object to COM notice that when they try and use the object in VB6, none of their methods are listed. Create a quick .NET class library that will be exposed to COM to see why that happens: [VB.NET]

Option Strict OnOption Explicit On

Namespace QuickNET Public Class Bee Public Sub FindFlowers()

End Sub

Public Sub MakeHoney()

End Sub End ClassEnd Namespace

[C#]

using System;

namespace QuickNET{ public class Bee { public void FindFlowers() { }

public void MakeHoney() { } }}

Now create a COM type library from this .NET component to see what it looks like (this doesn’t actually register it for COM – it just creates a COM type library). Go to a Visual Studio .NET Command Prompt (Start, Programs, Microsoft Visual Studio .NET, Visual Studio .NET Tools, Microsoft Visual Studio.NET Command Prompt), change to the directory of the above compiled .NET component and enter the following command:

TLBEXP.EXE QuickNET.dll /out:Com.QuickNET.tlb

The TLBEXP.EXE utility generates a COM type library from the .NET assembly. You can name the type library anything you want, but, by convention, it usually has a .tlb extension. I prefix my exported type libraries with “Com.”. Now load up OLE View and open the type library “Com.QuickNET.tlb”. Below are the relevant parts:

coclass Bee { [default] interface _Bee; interface _Object; };

interface _Bee : IDispatch { };

This looks very similar to VB6 COM type libraries. You can see that an interface called “_Bee” was created for the “Bee” class and it’s also the default interface. However, there are no methods on the interface. If you were to start up VB6 and add a reference to this tlb to your project, you’d notice by looking at the Object Browser that the Bee class has no methods (VB6 always looks at the “default” interface to see what methods are on the class).

NOTE: The _Object interface isn’t important for our discussion. Since everything inherits from the Object class in .NET and that class exposes a _Object interface, there’s a _Object interface added to all exported types.

So why didn’t TLBEXP.EXE put all of the methods on the _Bee interface? Since the layout of a COM interface is a binding contract, adding new methods to a .NET class and then regenerating the COM type library might change that layout – thus breaking existing COM clients compiled against the old layout. By defining an empty interface, all clients will do late-bound calls and new versions of the .NET component (and its COM wrapper) will work without recompiling the COM clients.

Taking ControlSo how do you get those methods on your .NET component to show up in VB6? You can take what you know about VB6 and COM and apply it to .NET. Basically, you need to:

Have an interface with your methods defined.

Make that interface the default interface.

The first one is easy. Add a .NET interface that includes the methods you want to expose to COM: [VB.NET]

The IBee interface came straight through as a standard COM interface – it even includes the methods. The “Bee” coclass even implements this class (as expected), but there’s still that (empty) _Bee interface that is marked as the default interface. And that’s where VB6 will look for the methods belonging to the class. But the IBee interface is exposed as a standard COM interface so you could do everything through that interface and it would work fine. For example, using the type library created above, this VB6 code is perfectly legal:

Dim bee As IBeeSet bee = New Beebee.FindFlowerbee.MakeHoney

To make a cleaner integration, however, the IBee interface needs to be the default interface. That is accomplished through attributes.

Attributes If you’re not familiar with attributes, here’s a quick summary. Attributes are a “descriptive declaration”. They’re used to “annotate” programming elements such as types, fields, methods, classes, etc… Attributes can have values associated with them and those values, along with the attribute information, are saved with all of the other .NET metadata. They can be used to describe code to the CLR (Common Language Runtime) or to affect application behavior at runtime. To control how TLBEXP.EXE creates the type library, you can use an attribute to prevent it from creating that “default” interface. The “ClassInterfaceAttribute” can be applied to a class with the “ClassInterfaceType.None” enumeration member. It can also be applied at the Assembly level where it would apply to every public class in the Assembly. Using the example above, you can make a small modification to the Bee class and apply the attribute: [VB.NET]

Not only do you not have the “_Bee” interface, but your IBee interface is marked as the default interface. Why is that? If the ClassInterfaceAttribute specifies that no automatic interface is to be generated, TLBEXP.EXE will take the first interface implemented by the class and make it the default interface. So if you plan on exposing your .NET class to COM, take into account which interface is the first interface implemented in the source code (either through the VB.NET “Implements” keyword or the first interface listed after the “:” in your C# class definition).

Controlling Your GUIDs The last thing you need to control is your GUIDs – Globally Unique Identifiers. You’ve probably seen a GUID before. Here’s a sample:

82CC3E6A-148E-4b77-866E-598DBEDC5C74

Every interface in COM and every coclass (creatable class object) is identified by a unique GUID. VB6 controls GUID creation for you. You can “coax” VB6 into using the same GUIDs for classes and interfaces by using the “Binary Compatibility” mode of your VB6 project when recompiling. The .NET TLBEXP.EXE utility will also auto-generate a GUID for every interface and class it exports to COM. But you can use attributes to define the GUID yourself. Why should you care? Whenever you register a .NET object as a COM component, registry entries are created. Some of those registry entries are the GUIDs used to identify your classes and interfaces to COM. If you don’t specify a specific GUID, TLBEXP.EXE will generate a new one every time you re-create your COM type library. COM clients already developed could have references to the old GUID and would no longer work since the GUIDs changed. Likewise, if you do control and define a specific GUID for your classes and interfaces, then the GUIDs aren’t changing and your COM clients won’t need to be recompiled and will continue to work even with new versions of your .NET component. You can use attributes to define a GUID for your classes and interfaces. Instead of trying to “make up” your own unique GUID, VS .NET (along with previous versions of Visual Studio) comes with a tool for generating a GUID called (interestingly enough) guidgen.exe. This should be found in the “\Program Files\Microsoft Visual Studio .NET 2003\Common7\Tools” directory. Double-click on it and you should see a screen similar to the one below: GUIDs are used in many different places, so guidgen supports creating a GUID in four different formats. For your purposes, you need the fourth format: Registry Format. You don’t need the opening and closing braces, but you can trim those off. Press “New GUID” to generate a new GUID and then “Copy” to copy it to the clipboard. Now define a GUID for your IBee interface (make sure you’ve added the System.Runtime.InteropServices namespace to your code). Paste the clipboard into the “Guid” attribute and remove the leading and trailing braces: [VB.NET]

You’ve been using the TLBEXP.EXE utility throughout this article to generate a COM type library. That’s because, so far, you’ve only been interested in seeing how .NET exposes its structures to COM. To actually make the .NET component look like a COM component, you need to register it just like any other COM component. I’m sure you’re familiar with regsvr32: the utility for registering and unregistering COM components. This utility won’t work for a .NET component. Instead, you’ll need to use the .NET utility “regasm.exe” – short for “Register Assembly”. This utility adds registry entries to make your .NET component “look” like a regular COM component. The REGASM.EXE utility also has the option to generate a COM type library which can be used by VB6. The “/tlb” option on REGASM performs the same thing that TLBEXP.EXE does. Therefore, you really don’t need to use TLBEXP when creating a .NET object for COM. Just use REGASM with the /tlb option. Here’s an example. Go to the Visual Studio .NET 2003 Command Prompt, change to the directory of your .NET assembly, and enter:

REGASM myassem.dll /tlb:com.myassem.tlb

Your object is now registered as a COM component, and you have a COM type library you can reference from VB6 to early-bind to the component. Now all you need to do is get COM to find the .NET assembly.

Local Deployment or the GAC? Once your .NET assembly is registered as a COM component, any attempt to create an instance of one of the .NET components from COM will cause a copy of the .NET runtime to be loaded. The .NET runtime will then need to locate the assembly. Even though you’re running in a COM environment, the .NET rules for finding an assembly still apply:

Tirst, the Global Assembly Cache (GAC) is checked.

Then, the local directory is checked.

The second option is a bit easier but not as flexible. For the first option, simply copy the .NET assembly to the same directory as your COM exe client and the runtime will find it. However, if you’re building/debugging in the VB6 IDE, then the “local directory” is the location of VB6.EXE. In this situation, you need to copy your .NET assembly to different locations depending on whether you’re running inside the VB6 IDE or not. And copying files into the same directory as VB6.EXE isn’t a great idea. If you make any updates to the .NET assembly, you need to make sure you copy it to both locations. For these reasons, placing the assembly in the Global Assembly Cache (GAC) is usually the best option for COM Interop. Before placing an assembly in the GAC, you need to make sure you’ve got a fixed versioning scheme and a strong-name key pair. Getting a fixed versioning scheme is simple: In your AssemblyInfo file, change the value of the AssemblyVersion attribute from the default “1.0.*” to “1.0.0.0”. The version number is a key component of placing an assembly in the GAC. Leaving the “*” makes VS .NET generate a new value every time you build your project. Since other projects that reference your assembly look for a specific version number, having it change every time you build is a problem! Therefore, hard-code a specific value and as you develop new releases of your assembly, increment the version number as appropriate. Next, you’ll need to generate a strong-name key pair. Use the SN.EXE tool by going to the Visual Studio .NET 2003 Command Prompt, changing to the directory of your .NET project and enter:

sn -k mykey.snk

Now update the AssemblyKeyFile attribute in your AssemblyInfo to point to the “mykey.snk” file. Finally, recompile your .NET component. It is now ready to be added to the GAC. Go to a Visual Studio .NET 2003 Command prompt, change to the directory of your .NET assembly and enter:

gacutil -I myassembly.dll

This installs your assembly into the GAC. Now, the runtime can locate the assembly no matter which COM client instantiates your .NET component. Summary of Best Practices This article has covered a lot of ground. Here’s a review of the best practices for hassle-free COM Interop:

Define a .NET Interface for the methods you want to expose to COM.

Assign a GUID to that interface with the “Guid” attribute.

Have your class implement your interface as the first interface.

Assign a GUID to that class with the “Guid” attribute.

Add the “ClassInterface(ClassInterfaceType.None)” attribute to prevent regasm/tlbexp from creating an empty default interface.

Hard-code a specific version number in your AssemblyVersion attribute.

Create a strong-name key pair for your assembly and point to it via the AssemblyKeyFile attribute.

Add your assembly to the GAC,

Register your assembly for COM by using the REGASM command along with the “/tlb” option to generate a COM type library.

VB6 projects can add a reference to the generated type library to receive the benefits of early binding. Scripting clients like VBScript can also access the object, but they’ll only be able to access the methods on the default interface. When it comes time to enhance your .NET component, don’t touch your existing interface. If you need to add more methods, create a new interface (with a Guid) and implement that interface. Changing the existing interface could break clients already compiled against that interface.

GnuPG Wrapper

This article presents GnuPGWrapper v1.0, a wrapper class for GnuPG.GnuPG stands for GNU Privacy Guard and is GNU’s tool for secure communication and data storage. It can be used to encrypt data and to create digital signatures. It includes an advanced key management facility and is compliant with the proposed OpenPGP Internet standard as described in RFC 2440. As such, GnuPG is a complete and free replacement for PGP (Pretty Good Privacy).This article provides a C# wrapper class (GnuPGWrapper) that will enable the use of an OpenPGP Internet encryption standard within a .NET world. It is shipped with a demo ASP.NET Web Form (GnuPG.aspx), which calls the wrapper class.

Implementation

GnuPG ships as a command line program (gpg.exe) acting as a filter (reads from standard input and writes into standard output). Although suitable for scripting on UNIX systems (where calling a command line program from “sh” or “bash” is easy), it’s pretty hard to integrate this in a production .NET environment.The GnuPG Wrapper executes the command line program (gpg.exe) in a different process, redirects standard input (stdin), standard output (stdout), and standard error (stderr) streams, and monitors the streams to fetch the results of the encryption/signing operation. The GnuPG Wrapper:

Doesn’t use any temporary files to store results; it directly uses streams/pipes.