By david on September 06, 2010

In recent project, we encountered a business model that seemed to naturally lend to implement table inheritance. It was non-trivial to implement in database model; there were quite a few different ways to do this. Finally, we decided to use table-per-type inheritance and we used Entity Framework 4 as our ORM tool.

Here are several things that we learn:

First, in EF-4, there are multiple ways to implement table inheritance (check the third blog post below for more detail). In summary though, if you want performance - go for Table-Per-Hierarchy, but you lose flexibility and database validation among other things (in our case, performance is not yet a paramount issue).

Second, we need to model one-to-either constraints. Here is an example model diagram (not the real one).

TPT Example

For a given item, if it is a Car, our business model require that same itemId can not appear in other sub-tables (Motorbike and Accessory), it can only appear once in its hierarchy tables (Car, Vehicle, and Item). To address this we added a 'type' field in both the parent and the child table, enforce that field to be 'constant' in the child-table (e.g. we use PERSISTED field in SQL Server) and then apply an FK for the ItemId and the 'type' field (check the fourth blog post below for detail).

Third, we encounter several hurdles in implementing the TPT Inheritance in EF-4 - mostly because we need to get the data model just right so we do not have to hack EF-4. In some ways it is a good thing, because later we realize that it is actually kind of forcing our data model to be clean. So, here are a few tips that helped us implement this cleanly in EF-4:

1) Make sure only a single field PK throughout the inheritance chain (e.g. ItemId).

2) Use constraint on the parent to allow the FK from sub to work. (we can't have an FK ItemId, ItemTypeId to the Item table unless those combo is a unique key on the Item table). E.g. on the Item table, apply CONSTRAINT Item_AltPK UNIQUE (ItemId, ItemTypeId).

3) In EF Designer, on the child table, make sure to rename the Model's (not the Store's) xxxTypeId field (e.g. xxxTypeIdPersisted) - and map it to the sub table xxxTypeId field. Then, in code, just don't do anything to that field (it's a PERSISTED field on the sub table).
 
4) You can then have *n-level of inheritance* as well as one-to-either constraint this way... and no single error on the EF designer yay... life is good!!!


Finally, here are a few blog posts that has helped us:

Step-by-step example on how to implement Table-Per-Type Inheritance in Entity Framework 4

Step-by-step example on how to implement Table-Per-Hierarcy Inheritance in Entity Framework 4

A must read before deciding whether to use Table-Per-Type or Table-Per-Hierarchy

A Solution to implement One-to-Either Constraints

 

By Richard Raseley on August 03, 2010

Introduction

Forefront Unified Access Gateway 2010, formerly known as Intelligent Application Gateway, is Microsoft’s current generation solution for providing remote access to internal resources.

One of the exciting features in UAG is the ability to publish internal web applications through a secure portal. This allows you to control who has access to what applications and enforce certain security requirements on computer / device that the user is accessing the site from.

Pre-Configuration Tasks

Before you begin the publishing tasks you will have to decide on the namespace you want to use and procure the certificates to match the space. In our example we will be using the address portal.domain.com to publish the UAG portal site.

Keep in mind that when publishing applications via this portal site, all applications will require an address that exists under the top level portal address. For example, when publishing a SharePoint site, you will have to assign it an address like sharepoint.portal.domain.com.

In addition to the DNS entries that must be created to facilitate the solution (portal.domain.com and sharepoint.portal.domain.com in our example), a certificate must be created that will cover the portal and all the sites underneath it. The best option in this situation would be to obtain a wildcard certificate that covered the portal.domain.com site and all sites underneath it. You could also obtain (or create) a certificate that covered the portal.domain.com site and also contained all the application sites you wish to create as Subject Alternate Names.

Creating SSL Trunk

To create the portal trunk that we will use to publish applications, first open up the Forefront Unified Access Gateway Management Console. In the left pane, right click on HTTPS Connections and choose New Trunk. Please note that we will be accepting defaults for most of the configurable options in this section.

In the Welcome to the Create Trunk Wizard screen, click next. In the Select Trunk Type screen, ensure Portal Trunk is selected and click next. In the Setting the Trunk screen enter the Trunk Name (just a friendly name which the trunk will go by), the Public Host Name (which is the external URL that the trunk will be accessed from – portal.domain.com in our example), ensure the proper IP address and ports are selected, and click next. In the Authentication screen, click the Add button and select one of your Domain Controllers to use for authentication of users, and click next. In the Certificate screen, select the certificate that you have procured in the previous step and click next. In the Endpoint Security screen, click next. In the Endpoint Policies screen, click next. In the Completing the Create Trunk Screen, click finish.

Your portal has now been created with default options! At this point, please use an external connection to navigate to https://portal.domain.com and view the result.

Publishing SharePoint Application

To publish the SharePoint web application, first open up the Forefront Unified Access Gateway Management Console. In the left pane, expand HTTPS Connections, right click on the Trunk you created in the previous section, and click Add Application. Please note that we will be accepting defaults for most of the configurable options in this section.

In the Welcome screen, click next. In the Select Application screen, fill the radio button next to Web and choose Microsoft SharePoint Server 2010 from the Web drop down list. In the Configure Application screen, enter the Application Name (just a friendly name which the application will go by) and click next. In the Select Endpoint Policies screen, click next. In the Deploying an Application screen, ensure the Configure an Application Server radio button is filled and click next.

In the Web Servers screen, double click in the blank space to the right of Addresses and enter the URL (excluding the HTTP/S://) that you use to access your SharePoint 2010 site internally, in the Public Host Name field enter the DNS name you have given the site (in our example you would enter “sharepoint.portal”), fill the checkbox next to Replace the Host Header with the Following and in the associated box type the URL that you use to access your SharePoint 2010 site internally, and click next.

In the Authentication screen, click Add and add at least one Domain Controller that users will authenticate against, then click next. In the Portal Link screen, click next. In the Authorization screen, click next. In the Completing the Add Application Wizard, click next.

Conclusion

When properly configured, Forefront Unified Access Gateway 2010 is a powerful tool for providing remote access to your internal web applications (and many more internal resources). In my example I accepted mostly default settings, however there are many powerful options available to help you control access, security, and endpoint compliance.

By david on August 03, 2010

Image caching at the browser level is one of the most efficient way to boost web site performance.

In some of our web application, we have to render dynamic images stored in Azure Blob Storage. Without image caching at the browser level, rendering these images at the browser will be a huge performance hit, in particular when we have 20-30 images to render in a given page.

Here are some of the techniques we have used in the past:

  1. Sent an ETag value in the HTTP response to avoid unnescessary network bandwidth.
  2. Sent an Expires value in the HTTP response to avoid server calls within short period of time.

The result of these two technique yielded a much better user experience while still maintaining the ability to render dynamic images in the browser.

Here are the rundown:

1. Sent an ETag value in the HTTP response
By sending a unique ETag value in the (original) HTTP response (it can be any format of a string), the next time the browser was going to fetch the same image (any URI - as a matter of fact), it would include the "If-None-Match" header with the ETag value in the request. So, at the server side, we could simply check the ETag value in the response as well as the current ETag value of the image (or any resources in general), if they were the same, then the server would simply send HTTP Response 304 - Not Modified, instead of the image. The browser would then use the image in its cache instead. This was a lot less Network Bandwidth.

Below would be what the HTTP Response and Request look like:

Original Response: HTTP/1.1 200 OK Cache-Control: private Content-Type: image/jpeg [... deleted] Etag: 5a3b14bfb9dc15dd0823b3a647681d50 [... deleted] Date: Tue, 03 Aug 2010 14:24:08 GMT Content-Length: 1777

Subsequent Request (as long as the browser still retain its cache):

GET [uri address] HTTP/1.1 Host: [host address] User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 [... deleted] If-None-Match: 5a3b14bfb9dc15dd0823b3a647681d50

The Response to this subsequent Request:

HTTP/1.1 304 Not Modified Cache-Control: no-cache Pragma: no-cache Content-Type: text/html [... deleted] Date: Tue, 03 Aug 2010 14:26:01 GMT

That's all it on the HTTP Response. Nothing on the body. Very efficient network bandwidth utilization.

2. Sent an Expires value in the HTTP response
Eventhough the above technique would make the web page loads faster, it would still make server calls, and if we had 20-30 images on the page, that would still add up. So, the next thing we could do to improve user's experience, at least within the duration of the visit to the web site, we also sent HTTP Header "Expires" in the original response. What this did was to let the browser knew, that the next time it neededs the same image (any URI in general) - it would check the datetime stamp on this Expires field and if the image/resource did not yet expire, it would not try to fetch it from the server. We did this when it was not critical for the user to get real-time dynamic resource update. E.g. if someone updated the image, it was OK for the rest of the users to see the new image within the next half hour or so. BTW, user could always hit Ctrl+F5 (in most browsers) to force a refresh.

Below would be what the HTTP Response look like:

HTTP/1.1 200 OK Cache-Control: private Content-Type: image/jpeg Expires: Tue, 03 Aug 2010 15:04:03 GMT [... deleted] Date: Tue, 03 Aug 2010 14:34:03 GMT Content-Length: 93870

So, after the first time image(s) were fetched (or get the 304 Not Modified Response), within the next 30 minutes, as user browsed the web site, any request for the same image(s) would simply be retrieved from the local browser cache, no trip to the server whatsoever.

Much better user experience.

By shannon on July 08, 2010

We recently had a case on a new ASP.Net web application where we needed to add a value to the Handler Mapping in IIS. This was to enable the use of local SQL Server Reporting functionality in the MVC 2.0 web application.

When the mapping was originally configured, it was added with a typo. This was easy enough to fix and everything seemed to work well. Eventually the reporting stopped working, and after troubleshooting the issue, it was discovered that the Handler Mapping was once again set back to the version with the typo.

First thoughts were that there was something in the build/deployment process that was setting this, a script or something. After walking through the deployment process step by step, it was determined that just restarting IIS was resetting the Handler Mapping to the version with the typo in it.

This seemed really odd, and short of deleting the web application and starting from scratch, hoping that this issue would be resolved, I was looking for a less destructive fix.

It turned out to be fairly simple. With a couple adjustments to the web.config for the application, the issue has been fixed.

We had originally created a Handler Mapping entry similar to the following:

Path:
Reserved.ReportViewerWebControl.axd

Type:
Microsoft.Reporting.Microsoft.Reporting.WebForms.HttpHandler, Microsoft.ReportViewer.WebForms, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a

Name:
Reserved-ReportViewerWebControl-axd

What we wanted was actually:

Path:
Reserved.ReportViewerWebControl.axd

Type:
Microsoft.Reporting.WebForms.HttpHandler, Microsoft.ReportViewer.WebForms, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a

Name:
Reserved-ReportViewerWebControl-axd

To fix this issue we added the following 2 lines to the web.config:

<remove name="Reserved-ReportViewerWebControl-axd" />

and

<add name="Reserved-ReportViewerWebControl-axd" path="Reserved.ReportViewerWebControl.axd" verb="*" type="Microsoft.Reporting.WebForms.HttpHandler, Microsoft.ReportViewer.WebForms, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" resourceType="Unspecified" requireAccess="Script" preCondition="integratedMode" />

These lines went into the section shown below making the section look similar to the following:

<system.webServer>
	<handlers>
		<remove name="Reserved-ReportViewerWebControl-axd" />
		<remove name="WebServiceHandlerFactory-Integrated"/>
		<remove name="ScriptHandlerFactory"/>
		<remove name="ScriptHandlerFactoryAppServices"/>
		<remove name="ScriptResource"/>
		<remove name="MvcHttpHandler"/>
		<remove name="UrlRoutingHandler"/>
		<add name="ScriptHandlerFactory" verb="*" path="*.asmx" preCondition="integratedMode" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
		<add name="ScriptHandlerFactoryAppServices" verb="*" path="*_AppService.axd" preCondition="integratedMode" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
		<add name="ScriptResource" preCondition="integratedMode" verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
		<add name="MvcHttpHandler" preCondition="integratedMode" verb="*" path="*.mvc" type="System.Web.Mvc.MvcHttpHandler, System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
		<add name="UrlRoutingHandler" preCondition="integratedMode" verb="*" path="UrlRouting.axd" type="System.Web.HttpForbiddenHandler, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/>
		<add name="Reserved-ReportViewerWebControl-axd" path="Reserved.ReportViewerWebControl.axd" verb="*" type="Microsoft.Reporting.WebForms.HttpHandler, Microsoft.ReportViewer.WebForms, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" resourceType="Unspecified" requireAccess="Script" preCondition="integratedMode" />
	</handlers>
</system.webServer>
By david on June 30, 2010

One of the nice thing we like about Linq to Entity here in Palador is the ability to form the IQueryable to ensure performance - by minimizing amount of data traveling across the wire.

We have the following data model:

PersonaLink

In one repository method, we need to get a given Persona, AboutMe field which is in auxilary table - the list of its PersonaLink (read that as : “Things I Like” that list my favorite urls), along with it the value of the LinkBitmapId.

We do not need nor want to grab PersonaProfile.Photo.

We also do not want to use this syntax to get to the PersonaLink.LinkBitmapId - without making extra round-trips (using lazy loading, it would be one for each record in PersonaLink property) and/or grab the varbinary field LinkBitmap.Bitmap:

dbPersonaLink.LinkBitmapReference.EntityKey.EntityKeyValues[0].Value

– which is quite ugly.

So, we would need to do EF Projection - and yes, we know Include will not work – we don’t want it anyway, since we want also to do projection on the property (LinkBitmap) of the collection property (PersonaLink) of the Persona.

So, after spending some time scouring the Internet and tinkering with Linq to Entity – we get the following to work:

var dbPersona = (from p in context.Persona where p.PersonaID == personaId select new { p.PersonaID, p.NickName, p.ContributorRank, p.EmailAddress, p.PersonaProfile.AboutMe, p.DefaultPartner, p.DefaultGeo, PersonaLink = (from pl in p.PersonaLink select new { pl.Description, pl.Url, pl.LinkBitmap.LinkBitmapId}) }).FirstOrDefault();

After getting back the data I want in a single trip to database in dbPersona - we could then simply ‘unwrap’ this dbPersona instance (anonymous type) and put the data we want into a new instance of Persona and return that thing.

We also obtained the generated SQL and examine it. It turns out to be not too bad – a whole bunch of joins and no crazy subquery.

We hope this might help or trigger some ideas in exploring Linq to Entity to do things which we wished we could do in EF (in particular for achieving more optimum performance).

One thing we found in scouring the Internet is that ObjectQuery method – are rather limited compared to Linq to Entity. It seems that there is no way to do nested projection (involving collection) using ObjectQuery method in EF.

By on June 24, 2010
Summary

Direct Access is an exciting new remote access solution that has been released as a stand-alone feature, or part of Microsoft's Forefront Unified Access Gateway 2010. With Direct Access, you can provide remote users with an extremely robust experience - allowing access to internal resources such as applications, internal sites, and files just as if you were physically located on the network - and all this without any sort of VPNs or special user configuration! In addition to the simplicity it offers, Direct Access creates a truly bi-directional connection with the remote client, allowing the continual enforcement of company security policies regardless to whether or not the user is logged on.

Technical Overview

Direct Access is built upon two standards-based technologies, IPsec (with either 3DES or AES encryption) and IPv6. Authentication and communication from client to server is handled via two separate tunnels.

Firstly, an IPsec tunnel is established between the client and Direct Access server using the computer certificate. This tunnel is intended to provide access to Domain Controllers and Domain Name Servers to allow the computer to process group policy and create a secure channel to facilitate user authentication.

Secondly, an IPsec tunnel is established between the client and Direct Access server when the user enters their credentials and initiates a logon request. This is the tunnel that will actually connect the user to the internal network and allow for traffic to pass back and forth.

Now that both tunnels are established, the user has complete (or limited – depending on how you configure security) access to all internal network resources – just as if they were on location inside the network! In addition to the simplicity of the solution, the fact that it uses IPsec tunnels means that it will traverse any firewall that the client is located behind – even those that traditional VPNs had trouble getting through.
By Joe Beernink on June 15, 2010

The systems development world today is all about instant gratification.  Web search results must return in 1.2 seconds or less.  Web pages must load in less than 3 seconds.  Search results not only must find every result for ‘Flugenschnitzel’, it must show the most popular references to ‘Flugenschnitzel’ in the last 30, 60 or 90 days.  All of these things matter to users.  People want the most up to date information possible, and they want it now.

But what do you do what wanting up to date and means that the page take too long to load?  You make an intelligent choice. 

For instance, if you are calculating the most popular product on a site, if the ranking of that product is five minutes old, it usually doesn’t matter.  If you are calculating the remaining amount in a bank account, it does matter, so the following approach doesn’t apply, and the user may need to wait a fraction of a second longer because they need to see absolutely accurate information all the time.

We recently had scenario A.  There were three lists of products on a page, sorted by Most Recently Updated Products, Most Popular Products, and Featured Products.  The page as originally written and tested here on our development servers took no time at all to load.  But when we moved the site to Windows Azure, and put it under load, performance dropped dramatically.   It didn’t take long to understand why.  There was a greater latency between the client and the server and the server and the database.  Each round trip we were making to the database or to the server came at a cost.  We couldn’t control the round trip latency, but we could control the number of trips. We started to tune the result set to reduce the amount of data needed for each list.  We improved our client side caching so that fewer graphics were being brought down. 

But one query kept slowing down the page refresh, and it got worse as more data was added to the site.  It was the Most Popular Product query.  What was happening was that every time the page refreshed, the popularity of all records was being calculated.  Obviously not a good idea now, but when we laid out the site, it was a minor query, and a minor part of the site.  We didn’t tune it until we needed to, which is arguably a good thing.

We considered our options.  We could have the popularity update every time someone used or viewed the product, but that would cause those actions to be slower.  We could cache the results for a few minutes on the server side, but someone would have to pay the price for the slow query, and that would also be bad.

We decided to create a new worker role in Azure that wakes up every few minutes, calculates the popularity (and a few other key metrics), and then goes back to sleep.   The worker role runs out of sight of the user, and populates a flattened metrics table that is easily and quickly queried.  The views used by the MVC application never had to change, but we did change the data access layer to use these new fields.  It took about four hours to build and deploy the new Accumulator, and as soon as the deployment was complete and the stats updated, the site went from 7 seconds for the home page refresh to less than 1 second.  The users never know, and rarely care that the list is a few minutes old.  They want the instant gratification of a quick page load.

Doing batch programming like this isn’t anything new.  And although the solution was quick and easy using an Azure worker role, it could be a little better if it were a scheduled job instead of one that was always running and sleeping.  The Azure platform charges by CPU usage, so it would be really nice if the job wasn’t always there running up the charges.  But in this circumstance, we had a site that was unusable due to performance, and the ability to deploy this type of solution quickly really kept the project on time and let us focus on enhancing the user experience instead of worrying about infrastructure.

By ryan on June 10, 2010
There's been a lot of buzz around the capability of Windows Server 2008R2's ability to utilize Cluster Shared Volumes (CSVs). CSVs provide the ability to use a single LUN in clustered Hyper-V deployments. They grant better space utilization, easier management, and the file-lock approach (as opposed the LUN lock) allows for some amazing capabilities. In most situations, this is ideal. There are some situations, however, where CSVs don't make sense. What if you're using the advanced capabilities of your storage devices to mirror your data to another site? In the CSV scenario, you have an all or nothing DR scenario. But if you're using a hot/hot site recovery design, you may just want to use the multi-site capacity to handle individual machine hard fails. Or you may want to move a department and its servers from one site to another. In this case, individual LUNs can provide that functionality. While I realize that most environments don't need these capabilities, they can be very attractive to more dynamic companies who wish to have a fast-up DR scenario.
By shannon on June 03, 2010
Recently, I was asked about doing a find and replace for Word documents in code. We had sections that needed to be conditionally shown, based on specific criteria. This meant that the Word document template contained 2 different sections, but after the code ran, only one of them should remain. Since I had never done this, I did a little searching. I found a large number of posts on various ways to do this, but none of them seemed to do exactly what I wanted, and in many cases they didn't seem to work as I was expecting.

I knew the logic, that would work, but it was a matter of figuring out how to actually find and replace the pieces using the Word interop objects. We added Tags to the document to mark the beginning and ending of the sections that we needed to work with.

First I got it working to delete the section of content that I wanted to "hide". Then, I had to remove just the tags for the section we were going to leave. This left me with just the section of text we wanted.

So just say we started with a very simple Word document that looked something like this:

Here is the start of our document.
[FirstTagToFindStart]This is our first section.[FirstTagToFindEnd][SecondTagToFindStart]This is our second section.[SecondTagToFindEnd]
Here is the end of our document

At the end, we want the document to look like this:

Here is the start of our document.
This is our second section.
Here is the end of our document.

Here is the code that seemed to do the trick:
Word.Application word = new Word.Application();
Document doc = new Document();
// Set our missing object as we are required to pass it for any param that we are not setting below
object missing = System.Type.Missing;

// Open our word document
object fileName = @"c:\wordtest\template.doc";
doc = word.Documents.Open(ref fileName, ref missing, ref missing, ref missing, ref missing, 
    ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, 
    ref missing, ref missing, ref missing);
doc.Activate();

try
{
    // set our search range to the entire document
    Word.Range beginSearchRange = doc.Content;

    beginSearchRange.Find.Text = "[FirstTagToFindStart]";
    beginSearchRange.Find.Execute(ref missing, ref missing, ref missing, ref missing, ref missing, ref missing,
                      ref missing, ref missing, ref missing, ref missing, ref missing, ref missing,
                      ref missing, ref missing, ref missing);

    object sectionStart = beginSearchRange.Start;

    Word.Range endSearchRange = doc.Content;

    endSearchRange.Find.Text = "[FirstTagToFindEnd]";
    endSearchRange.Find.Execute(ref missing, ref missing, ref missing, ref missing, ref missing, ref missing,
                      ref missing, ref missing, ref missing, ref missing, ref missing, ref missing,
                      ref missing, ref missing, ref missing);

    object sectionEnd = endSearchRange.End;

    Word.Range deleteRange = doc.Range(ref sectionStart, ref sectionEnd);

    // Check to make sure we don't just delete the whole document if not found
    if (deleteRange.Start != doc.Content.Start && deleteRange.End != doc.Content.End)
    {
        deleteRange.Delete(ref missing, ref missing);
    }

    // Need to also delete the tags for the section we are going to keep in the document
    Word.Range removeStartTagRange = doc.Content;
    removeStartTagRange.Find.Text = "[SecondTagToFindStart]";

    removeStartTagRange.Find.Execute(ref missing, ref missing, ref missing, ref missing, ref missing, ref missing,
                      ref missing, ref missing, ref missing, ref missing, ref missing, ref missing,
                      ref missing, ref missing, ref missing);

    // Can get both start and end from this one range
    // Check to be sure we don't delete the whole document
    if (removeStartTagRange.Start != doc.Content.Start && removeStartTagRange.End != doc.Content.End)
    {
        removeStartTagRange.Delete(ref missing, ref missing);
    }

    // Now do the same thing for the Ending alternate tag
    Word.Range removeEndTagRange = doc.Content;
    removeEndTagRange.Find.Text = "[SecondTagToFindEnd]";

    removeEndTagRange.Find.Execute(ref missing, ref missing, ref missing, ref missing, ref missing, ref missing,
                      ref missing, ref missing, ref missing, ref missing, ref missing, ref missing,
                      ref missing, ref missing, ref missing);

    // Can get both start and end from this one range
    if (removeEndTagRange.Start != doc.Content.Start && removeEndTagRange.End != doc.Content.End)
    {
        removeEndTagRange.Delete(ref missing, ref missing);
    }
}
catch (Exception ex)
{
    MessageBox.Show(ex.Message);
}
finally
{
    doc.Close(ref missing, ref missing, ref missing);
    word.Quit(ref missing, ref missing, ref missing);
    System.Runtime.InteropServices.Marshal.ReleaseComObject(word);
}
By david on May 24, 2010

In .NET, there is a performance penalty when using the try...catch block, in particular when the execution path hits the catch block during runtime. The general "wisdom" is to check for error condition when we can beforehand and only use try...catch if one or more of the methods called in the block may throw an exception that we want to handle (otherwise, let it bubble up as is).

The code is also more readable if we explicitly check for the error condition prior to entering the block rather then let the try...catch block does the error condition. The problem with try...catch used improperly for trapping error condition is the "reactive thought process" of - "What do I do now in the catch block?" I have seen numerous code (including myself before I learned the wisdom) one liner in the catch block that looks :

catch { // do nothing, just make sure we don't get runtime error }

OR

catch { // log error here }

This is a very sloppy programming style.

So, two things to keep in mind when about to use try...catch block:
1. If you can, don't use try...catch block. Maintain good programming style.
2. If the catch block to be executed significantly frequently, there will be noticable performance degradation.

For example, consider a method that attempt to parse an input string and extract some value from it (Assuming the expected input is in the form "Value:[value to extract]" and if input is not in the valid form, return null).

So, instead of the following code

public string ExtractValue(string input) { try { input = input.Trim(); var prefix = "Value:"; if (input.IndexOf(prefix) != 0) return null; return input.SubString(prefix.Length, input.Length-prefix.Length); } catch (Exception exc) { return null; } }

Note that if the function ExtractValue is called many times and the input values being passed are mostly null, it will raise the exception (that would get swallowed due to the catch - so nobody will notice it) - but you will get huge performance hit.


do this:

public string ExtractValue(string input) { if (String.IsNullOrEmpty(input)) return null; var prefix = "Value:"; input = input.Trim(); if (input.IndexOf(prefix) != 0) return null; return input.SubString(prefix.Length, input.Length-prefix.Length); }