Friday, December 28, 2007

Coding Standards and Design Guidelines

I get a lot of people at work asking me about our coding standards and guidelines. We do have some, but to be perfectly honest, they could be better.

I like to utilize the Code Analysis feature of the Visual Studio version I am running, and let the compiler help with warnings and errors when rules are broken. Unfortunately this is not available with all versions.

I also found two very useful articles on MSDN that help a lot with defining standards:

Development Books

A colleague sent me this link to an online book store in Australia that specializes in computer books (development, networking, project management, etc).



http://www.bookware.com.au

Postage should be a lot cheaper than ordering from Amazon, and the prices are way lower than our local stores in Perth.

Thursday, December 27, 2007

Optmistic Concurrency withTimestamps, LLBLGen and Web Services

Found a great article on how to implement optimistic concurrency with LLBLGEN and SQL Server:

Optmistic Concurrency and Timestamps in SQL Server Using LLBLGen Pro O/R Mapper by David Hayden.

Now, I am using XML Web Services and passing entities back and forth, and what I have found is that the DBValue property on each field is NOT serialized! I have not found a better solution as yet, but I am currently just using the field's CurrentValue. So, assuming the timestamp properties used do not get changed on the client, it will work, but this is a problem that will need to be fixed.

Update: Looks like there was an issue with the deserialization in version 2.5 (October 25 2007 release). The December release has apparently fixed this issue:

http://www.llblgen.com/TinyForum/Messages.aspx?...

Modifications with LLBLGEN 2.5

I am inherently lazy, which is a bad thing when it comes to coding, but the solution described by LLBLGEN's help and David Hayden relies on a factory class for each entity. Sure, we should probably modify the templates and create a new factory class for each of our entities, but for what I wanted, that sounded like too much work.

Now, in LLBLGEN 2.5, all entities are now derived from another generated partial class called CommonEntityBase. And, lets face it, we are probably going to create our timestamp field on every entity and call it the same name (in this case, every entity has a timetamp field called LastModified). So, I created a new partial class definition for CommonEntityBase that allows me to get access to the timestamp field I will use for all entities' concurrency control.

public partial class CommonEntityBase
{
private const string LAST_MODIFIED_FIELD_NAME = "LastModified";

public IEntityField2 LastModifiedField
{
get { return this.Fields[LAST_MODIFIED_FIELD_NAME]; }
}
}

This then allows me to create a single factory for concurrency predicate expressions:
public class EntityConcurrencyFactory : IConcurrencyPredicateFactory
{
public IPredicateExpression CreatePredicate(ConcurrencyPredicateType predicateTypeToCreate,
object containingEntity)
{
IPredicateExpression toReturn = new PredicateExpression();
CommonEntityBase entity = (CommonEntityBase)containingEntity;

switch (predicateTypeToCreate)
{
case ConcurrencyPredicateType.Delete:
case ConcurrencyPredicateType.Save:
// only for updates
toReturn.Add(new FieldCompareValuePredicate(entity.LastModifiedField,
null, ComparisonOperator.Equal, entity.LastModifiedField.CurrentValue));
break;
}
return toReturn;
}
}

Two classes for all entities - sounds good to me. Now, using David's example, there isn't any difference in the code (just every entity uses the same factory):
DataAccessAdapter adapter = new DataAccessAdapter(...);

BlogEntity blog = new BlogEntity();
blog.BlogId = 1;

adapter.FetchEntity(blog);

blog.Name = "New Name";

IPredicateExpression expression = new EntityConcurrencyFactory()
.CreatePredicate(ConcurrencyPredicateType.Save, blog);

adapter.SaveEntity(blog, true, expression);

You can still change optimistic concurrency strategies easily, but it is easier to apply to all of your entities at once.

Tag Cloud for Blogger

I found a neat bit of code to turn your standard tag list into a "cloud".

This one is okay: Compender by Raymond May Jr.

This one is better (in my opinion) and is the one I am using: New Blogger Tag Cloud / Label Cloud

Monday, December 10, 2007

Can't Connect to Machine via Remote Desktop

I had a machine I could not Remote Desktop (RDC) to. No matter what I did, I got the same error:

The connection was ended because of a network error. Please try connecting to the remote computer again.

In the System event log on the machine I was trying to connect to, I found quite a few Error entries with the source TermDD. This described the following error:

The RDP protocol component "DATA ENCRYPTION" detected an error in the protocol stream and has disconnected the client.

After a quick search, I found the following Microsoft KB article that helped me fix the problem:

"The RDP Protocol Component "DATA ENCRYPTION" Detected an Error..." error message

A reboot on the machine and it is now working fine.

Friday, November 30, 2007

Accessing the Current Principal in VSTO Add-In

I recently tried to get access to the Current Principal within an Outlook Add-In. Accessing the Identity was returning a blank name and an unauthorised user. Wierd.

It turns out the the VSTOLoader will load each Add-In into its own AppDomain. As such, you need to set the principal policy explicitly before you access the current principal for the first time.

Example:

AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);
string userName = Thread.CurrentPrincipal.Identity.Name;

As it running within an isolated environment, I am sure there are other issues you need to be aware of.

See the AppDomain Class in the MSDN Library for more information on application domains.

Thursday, November 29, 2007

Accessing Custom Resource Mailbox Properties With VSTO

In Exchange 2007 you can create custom resource properties to annotate your resources. For example, you may want to create a custom property called Vehicle and add this to all resources that represent vehicles in your Exchange organisation. The TechNet article, How to Create or Remove Custom Resource Properties, describes how this is done.

Getting access to these custom resource properties via Visual Studio Tools for Office (VSTO) is relatively straight forward, as long as you know exactly what you need to do! The problem is finding this with the documentation and newsgroup postings out there.

Anyway, access to this type of information is not available via properties on the Outlook Object Model. However, in VSTO 3 (for Outlook 2007), most Outlook objects have a PropertyAccessor object that allows you to get access to ALL the properties on the underlying MAPI object, not just the ones exposed by the COM interface. The GetProperty method takes a string identifying a property on the object and returns the value as an object. This string identifier consists of a namespace and some sort of property tag value. There are several namespaces that can be used, but the one used here is http://schemas.microsoft.com/mapi/proptag/. More information on referencing properties by namespace can be found in the MSDN article outrageously called Referencing Properties by Namespace.

Finding out the property tag value is next to impossible looking at the MSDN documentation. They simply don't document it, which I found incredibly frustrating. That is, until I found a copy of Outlook Spy. This is an excellent tool that allows you to browse the object model and also get access to the MAPI objects, including the elusive property tags!

Getting back to custom resource properties, I used Outlook Spy to examine one of my vehicle-type recipients. Under the AddressEntity property is a MAPIObject. If you "browse" this property, a window is displayed listing all of the properties of that MAPI object, including the property tag value, the type and its current value. On the right of the window is a field called DASL. This field is the value that you need to pass into the PropertyAccessor.GetProperty() method to extract its value. In my case, the property listing the custom resource properties was using the DASL http://schemas.microsoft.com/mapi/proptag/0x0806101E.

So, once you have this, the code is simple. The following example assumes you already have a Recipient object which is an Equipment resource with the custom property Vehicle.

public static bool IsVehicleResource(Recipient aRecipient)
{
bool result = false;

if (aRecipient.Type == (int)OlMeetingRecipientType.olResource)
{
try
{
//
// Get resource info property via MAPI property accessor.
// NOTE: this will throw an exception if it doesn't exist (ie: not a resource)
//
object resourceInfo = aRecipient.AddressEntry.PropertyAccessor.GetProperty(
"http://schemas.microsoft.com/mapi/proptag/0x0806101E");
//
// Split comma separated info into parts and look for information identifying
// the resource as Equipment and Vehicle.
//
string[] resourceDetails = resourceInfo.ToString().Split(',');
result = (resourceDetails.Contains("Equipment") && resourceDetails.Contains("Vehicle"));
}
catch (System.Exception ex)
{
// TODO: error handling
}
}

return result;
}

And that is it!

For more information on using the PropertyAccessor object, have a look at the MSDN documentation online.

Tuesday, November 27, 2007

Using LLBLGEN Generated Classes with Web Services

UPDATE: This only applies to version 2.0.

If you are using LLBLGEN with Web Services and you want to return entities and views to the client, you should have configured your machine to work according to the LLGBLGEN article titled Generated code - XML Webservices support.

This works nicely with Entity Classess, and probably Typed Lists (which I haven't used/tested yet), but there is a problem with Typed Views. If you have a Web Method that returns one of your Typed Views, you are probably getting errors generating the proxy classes, or the type specified in the proxy class that is generated does not match the Typed View in your Web Method!

There appears to be a bug in the webServiceHelper.template file that is used by the LLBLGEN generator. You can find this file in the following directory:

C:\Program Files\Solutions Design\LLBLGen Pro v2.0\Templates\SharedTemplates\Net2.x\C#

Open the file in a text editor and look for the following line in the "TypedView Classes" region:

return new XmlQualifiedName("<[CurrentTypedListName]>TypedList", namespaceToUse);

Change the above line to:

return new XmlQualifiedName("<[CurrentTypedViewName]>TypedView", namespaceToUse);

Now instead of having every one of your typed views with an XmlQualifiedName of TypedList, it is actually to the name of the class. Look in WebServiceHelper.cs (or WebServiceHelper.vb) to confirm this change is working.

I generally find that these changes only affect the proxy generation when the service reference is recreated; updating the reference doesn't always work.

Wednesday, October 17, 2007

Generating Documentation with Sandcastle

The following apps are required to get going with Sandcastle:

  • XP Service Pack 2
  • .NET 2.0
  • HTML Help Workshop
  • Microsoft Sandcastle
  • Sandcastle Help File Builder

First, ensure you have HTML Help Workshop by checking for the existence of the following folder:

C:\Program Files\HTML Help Workshop

If it is not there or does not contain hhc.exe, then download and install it from the following URL:

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/htmlhelp/html/hwMicrosoftHTMLHelpDownloads.asp

Microsoft Sandcastle can be found from here:

http://www.microsoft.com/downloads/details.aspx?familyid=E82EA71D-DA89-42EE-A715-696E3A4873B2&displaylang=en

Sandcastle Help File Builder can be found here:

http://www.codeplex.com/SHFB

You should also download the Presentation File Patches from the URL above and extract them into the Sandcastle folder.

Now you should run BuildReflectionData.bat in Sandcastle root directory to build reflection data for the .NET runtime.

Now launch Sandcastle Help File Builder and get going...

Wednesday, July 25, 2007

Free Visual Studio Add-ins

Here is an article listing some of the free Visual Studio Add-ins available.

I find Reflector for .NET extremely valuable, particularly when working with client's (somewhat untested) libraries!

Also check out CoolCommands and if you are using VB.NET get Refactor! for VB.NET - it provides the refactoring functionality that C# provides out of the box.

Monday, February 19, 2007

ClickOnce Deployment and Expired Temporary (Test) Certificates

I have recently been helping on a maintenance project for a new client, and we ran into an issue for our first deployment.

Basically, a test certificate had been used when the application was first deployed using ClickOnce deployment and had expired in December last year. Publishing through Visual Studio would not work due to the expired certificate and you get the following error:

The deployment identity does not match the subscription.

Crap! What now?

I found a Microsoft KB article related to the issue with nice concise title of "You receive an error message when you try to update a Visual Studio 2005 ClickOnce application after the certificate that was used to sign the installation expires". This gives some code that helps you renew a test certificate.

Great! Then I found someone who'd actually gone to the effort of making the code a little bit more robust and works with more certificates. You can find the project source and executable on Cliff Stanford's site RenewCert - Working Version.

This allows you to create a new certificate with the same key and extended expiry date. Publishing of subsequent updates should now work like a charm.

Wednesday, February 14, 2007

Getting the Version of a .NET Assembly at Runtime

The versions of all .NET assemblies are commonly located in the AssemblyInfo.cs file in each project. This can be extracted via code for use during execution and can easily be used to display version information on an About Box, for example.

Getting the version as a string is as straightfoward as the following code:

string version = Assembly.GetExecutingAssembly().GetName().Version.ToString();

The GetExecutingAssembly() method returns the Assembly of the executable that the code is running in. Other methods allow you to get the calling assembly or the Assembly containing a particular Type.

The GetName() method call returns an AssemblyName object, which provides information the assembly's unique identity, including the version, version compatibility, culture information and full name.

The Version property returns a Version object, providing access to the individual elements of the version (major, minor, revision, etc). It also provides overloads for comparison with other Version objects.

Wednesday, January 17, 2007

Identifying Memory Leaks in .NET Apps

Applies to .NET 1.0, 1.1 and 2.0.

This information has been extracted from the MSDN article, Identify and Prevent Memory Leaks in Managed Code, by James Kovacs.

Useful PerfMon Counters

Process/[Private Bytes]
Reports all memory that is exclusively allocated for a process and can't be shared with other processes on the system.

.NET CLR Memory/[# Bytes in All Heaps]
Reports the combined total size of the Gen0, Gen1, Gen2 and large object heaps.

.NET LocksAndThreads/[# of current logical Threads]
Reports the number of logical threads in an AppDomain.

Interpreting the Results

The following problems may be identified:

  • Thread Stack Leaks - [# of current logical Threads] increases unexpectedly

  • Unmanaged Memory Leaks - [Private Bytes] increases but [# Bytes in All Heaps] remains stable

  • Managed Memory "Leaks" - [Private Bytes] increases AND [# Bytes in All Heaps] increases

For detailed explanations on these, please read the MSDN article, Identify and Prevent Memory Leaks in Managed Code.

Wednesday, January 03, 2007

Error Installing SQL Server 2005 Express

After trying to install SQL Server 2005 Express Edition on my machine, I got through almost the entire install before it failed with an error message:

The SQL Server service failed to start. For more information, see the SQL Server Books Online topics, "How to: View SQL Server 2005 Setup Log Files" and "Starting SQL Server Manually."

Argh!

If you get this, you should be able to do a quick fix and then click on Retry. Unlike me, who clicked on Cancel and then had to go through almost the entire setup process again!

Anyway, if you look in your log file, you should see something like the following:

Error Code: 1067
MSI (s) (4C!44) [09:42:09:089]: Product: Microsoft SQL Server 2005 Express Edition -- Error 29503. The SQL Server service failed to start. For more information, see the SQL Server Books Online topics, "How to: View SQL Server 2005 Setup Log Files" and "Starting SQL Server Manually."
The error is (1067) The process terminated unexpectedly.
.

Error 29503. The SQL Server service failed to start. For more information, see the SQL Server Books Online topics, "How to: View SQL Server 2005 Setup Log Files" and "Starting SQL Server Manually."
The error is (1067) The process terminated unexpectedly.

Microsoft has a KB article about a fix for a error on install, but when I read the expected symptoms, it didn't quite look like it was a match. However, following the workaround in this KB article will fix your problem. Well, it fixed mine anyway.

The article can be found here:
http://support.microsoft.com/default.aspx/kb/920114

Note: the article talks about a Protect folder that requires changes to its permissions, but this folder did not exist on my machine. Creating the folder first and then applying the permissions worked like a treat.

Powered By Blogger