Posts Tagged ‘ .Net ’

Finding a Memory Leak in a .Net Application

Do You Have a Leak?

What do you do when you think your application has a memory leak?

I’m sure there are many options but this posting is about my experience with Red Gates ANTS memory profiler 5.1.

About Memory Management and the GC

There have been books written on this so I’m not going to attempt to explain. However I can’t stress enough how important it is to have at least a basic understanding about how the Garbage Collector works.

To compliment their products Red Gate have created a series of easy to understand on-line video’s about .Net Memory Management nicely broken down into several 5-10 minutes segments. These video’s are FREE so watch them!

If the video’s are not in depth enough for you, any article on the subject by Jeffrey Richter should satisfy your need for detailed explanations. Start with this one.

My Leak

Every time I opened and closed one of my controls, which was getting opened in a modal window, the memory used by the application increased and never went back down again. Which is weird because doesn’t .Net handle all memory management for me?

Do it does not.

So what is going on? The control in question has a dispose method, there’s nothing really tricky going on (no database connections etc) so how do I find out exactly what is causing the leak?

Finding the Leak

Enter ANTS memory profiler. I fire up the profiler, select my .exe and click ‘Start Profiling’.

Easy.

The app starts like normal but now the profiler has it under a microscope. Expect your app to run more slowly and make sure you have plenty of RAM.

I navigate to the screen where I can ‘launch’ the control that is leaking, then click ‘Take Memory Snapshot’.

Then I open and close the modal window say six times then click ‘Take Memory Snapshot’ once more.

Now we have two memory snapshots which we can compare. Stop Profiling for now, two is enough.

Click ‘Class List’, then in the grid click on the ‘Instance Diff (+/-)’ column header to sort by instance differences.

What we can clearly see now is a list of objects that are ‘alive’ in the program. What we care about is the difference in live instances from the first snapshot to the second. The ‘Instance Diff’ column provides this info. Now if we have a leak we should see an extra 6 live instances for our leaky control. So scroll down to the group of +6 items.

There are a couple of things of interest here in the profiler. First is yes we can see an extra six instance of our leaky control. Secondly, notice that ANTS puts your controls in bold. In this case we are looking for a specific problem but if you wanted to check for general memory leaks you can easily use the app for a while then scroll down until you see which of your objects is regularly increasing its instance count.

Ok great, we know it leaks, now what?

Dig a Little Deeper

Highlight the leaky object and click Instance List.

That will then show all 6 instance, just select one then click the ‘Object Retention Graph’ button.

In my case the graph appears empty, until I uncheck the ‘Hide’ box.

Now there’s some useful info…

In fact this tells me that there are several KeyEventHandlers that are stopping the GC from collecting my control.

Cool so back to the code and I add some code to unregister the handlers in the Dispose method.

_previousButton.Click -= PreviousButtonClick;
 _familyNameText.KeyDown -= Navigate;
 _givenNamesText.KeyDown -= Navigate;
...

Rebuild the solution and re-run the profiler. Take the initial snapshot, open close the leaky form half a dozen times, take the second snapshot.

Compare.

Now there are no more live instances of the leaky control! Our memory leak has been resolved.

Very easily!

Summary

It is almost certain that somewhere in your application there is a memory leak. With the right tool finding and resolving these leaks can be really easy, it just takes a little bit of time to familiarise yourself with the way the tool works.

The tools aren't cheap but for any commercial application they are most definately worth the money. In this posting I used ANTS profiler from Red Gate, I am sure there are other tools out there that also do a great job, I just haven't had the opportunity to use them. ANTS though is excellent (and no I do not have any association with them...beyond having bought a licence).

Events wired up to their handlers are often the 'hidden' cause of leaks. But even those of us who know how to manage memory in .Net often forget to do the right thing for whatever reason...usually time pressures. So I'd recommend explicitly building in some time into your project schedule to go hunting for memory leaks, find them before they go into production and everyone will sleep easier at night :-)

ClickOnce – Exception reading manifest from file

the manifest may not be valid or the file could not be opened

This is a problem that you can run into when you publish an application using ClickOnce.

The error message provided by ClickOnce is a little obscure and there may well be a number of different causes, this posting is about what was causing the problem in my case.

This is a more complete look at the error

What Causes the Problem?

Multiple references to the same dll(s) (not necessarily just a project reference).

In our case we were pulling in non .net dll’s from two different directories that each contained about 5 dll’s that existed in both directories. Same version and everything, versioning was not causing the problem.

As soon as we removed the duplicates the problem went away.

We also experienced the same problem when we were pulling a configuration file explicitly from one location but had also added the file to the main project.  So once again because a file with the same name was ‘included’ in the publish, ClickOnce throws an error because the manifest is invalid.

This guy found the problem was due to an Enterprise Library dll. I don’t know the details but I’d be willing to bet that he had a reference to two different versions of the same dll in two different projects.

Summary

While it would be nice to get a clearer error message I think what ClickOnce is doing here is pretty nice. It is making sure that you don’t get into any trouble with different references to the same file…which could be a different version and give you a world of subtle, very difficult to find bugs.

I hope this makes sense…it has been written very quickly :-)

MSBuild Customizable Targets

MSBuild has a number of targets that have been specifically created to be ‘overwritten’ or customized.

I have never seen a compiled list of these targets so here is a list of all the ones that I am aware of….

BeforeBuild
AfterBuild
BeforeRebuild
AfterRebuild
BeforeResolveReferences
AfterResolveReferences
BeforeResGen
AfterResGen
BeforeCompile
AfterCompile
BeforeClean
AfterClean
BeforePublish
AfterPublish

These targets are all safe to customize because in Microsoft.Common.targets they do not have any ‘implementation’, i.e. they get run but do absolutely nothing. You could (I believe) override any target you want to but if you do be aware that your ‘override’ entirely replaces what is in MSBuild. So if you absolutely must override a target that has an implementation, unless you completely understand 100% what you are doing, I recommend copying the full implementation and working your customization into the existing logic.

I would also strongly suggest that you NEVER modify Microsoft.Common.targets directly, that is just asking for pain.

ClickOnce – Creating Publish Page from msbuild

ClickOnce via msbuild

The Problem

When you publish from Visual Studio, the publish directory gets three files:-

  • Publish.htm
  • setup.exe
  • MyApp.application

but when you publish using msbuild you do not get the Publish.htm.

This post covers one approach to ensure you also get a nice publish.htm file. Actually it’s a two part blog, in the second part I’ll cover how to simplify your deployment process for multiple environments.

As a pre-requisite you’ll need to install msbuild community tasks.

All credit for this post belongs to my good friend Craig Hunter, this is pretty much a slightly modified version of his solution.

Step One – Create Customization File

This step in kind of optional. All subsequent steps may be done within your .csproj, it is just my preference to put all of my customizations into a separate file.

1. In your project file directory, create a new file called Customized.targets (actually call it whatever you want).
2. Now open your .csproj in notepad++, copy the first and last lines and add them to Customized.targets. Should look something like this

<Project DefaultTargets=”Build” xmlns=”http://schemas.microsoft.com/developer/msbuild/2003&#8243; ToolsVersion=”3.5″>
</Project>

3. At the bottom of your .csproj add these two lines

<Import Project=”Customized.targets” />
<Import Project=”$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets” />

What is not optional is adding the Import of the MSBuild community tasks.

Step Two – Add Publish Template

  1. In your project file directory, add a new directory called Publish.
  2. Add this file to that directory.

You don’t really need to but I also added the directory to my project. At the very least you do have to add it to source control (otherwise it won’t get to the build machine)

Step Three – Customizations

Add these customizations to your Customized.targets file. Remove the numbers, they are just there for reference below…

1.	<PropertyGroup>
		<BuildEnvironment>DEV</BuildEnvironment>
	</PropertyGroup>

2.	<Choose>
		<When Condition=" '$(BuildEnvironment)' == 'DEV' ">
		  <PropertyGroup>
		    <PublishDir>\\MachineIP\ReleaseDirectory\$(BuildEnvironment)\</PublishDir>
		  </PropertyGroup>
		</When>
		<When Condition=" '$(BuildEnvironment)' == 'QA' ">
		  <PropertyGroup>
		    <PublishDir>\\MachineIP\ReleaseDirectory\$(BuildEnvironment)\</PublishDir>
		  </PropertyGroup>
		</When>	</Choose>

3.	<PropertyGroup>
		<!-- Note this must be done AFTER the above Choose (so PublishDir is set)-->
		<PublishFilePath>$(PublishDir)publish.html</PublishFilePath>
	</PropertyGroup>

4.	<ItemGroup>
		<Tokens Include="PublisherName">
		  <ReplacementValue>$(PublisherName)</ReplacementValue>
		  <Visible>false</Visible>
		</Tokens>
		<Tokens Include="ProductName">
		  <ReplacementValue>$(ProductName)</ReplacementValue>
		  <Visible>false</Visible>
		</Tokens>
		<Tokens Include="ApplicationVersion">
		  <ReplacementValue>$(ApplicationVersion)</ReplacementValue>
		  <Visible>false</Visible>
		</Tokens>
		<Tokens Include="Prerequsites">
		  <ReplacementValue>@(BootstrapperPackage->'&lt;li&gt;%(ProductName)&lt;/li&gt;','%0D%0A')</ReplacementValue>
		  <Visible>false</Visible>
		</Tokens>
		<Tokens Include="Username">
		  <ReplacementValue>$(Username)</ReplacementValue>
		  <Visible>false</Visible>
		</Tokens>
	</ItemGroup> 

5.	<Target Name="AfterPublish">
		<Time Format="dd/MM/yyyy HH:mm">
		  <Output TaskParameter="FormattedTime" PropertyName="PublishTime" />
		</Time>
		<!-- Finalise the publish.htm template file and copy it to the publish location -->
		<TemplateFile Template="Publish\publish.template.html" Tokens="@(Tokens)" OutputFilename="$(PublishFilePath)" />
		<FileUpdate Files="$(PublishFilePath)" Regex="\${PublishTime}" ReplacementText="$(PublishTime)" />
	</Target>

1. More on the BuildEnvironment property in a later posting. It's not essential just remove all references to it if you want to remove it.

2. Also more on this in a later post, it is for specifying details for multiple environments. In the provided sample the PublishDir is the same machine and parent directory for both DEV and QA with a separating sub directory of the environment name. Don't forget to SHARE the ReleaseDirectory folder!

3. Tells MSBuild where to put the publish.html file (name it what you want)

4. The publish.template.html has a number of tokens which need to be set.  Adjust these how you want, add or remove whatever tokens you want in the template.

5. After MSBuild finishes publishing it will run this section which creates the publish.html file using the token values.

Save those changes and you are done, you should now be able to run MSBuild, call publish and have a publish.html created for you with relevant information.

Step Four - Run MSBuild

Open Visual Studio command prompt, navigate to your project directory, execute (this assumes you only have one project file in the directory):

msbuild /t:Publish /p:Configuration=Release /p:BuildEnvironment=DEV

Done!

Why Bother?

If you get the file from VS why then care about what happens when publishing directly from msbuild?

I can think of three reasons why you need to publish from msbuild.

First, ideally developers should never publish from their machines.  (I say ideally because I have to raise a guilty hand and confess this is currently what I am doing...sometimes cirumstance forces bad practice upon us). This means ideally you have a build machine and it is from this machine only that releases should be done. So if you want to use VS to do the publish then you need to install and licence that machine.

Secondly, you want to be able to do a release from the command line, you don't want to muck around starting VS, wait for the solution to load, open properties and click publish, what a waste of time, with msbuild you can create a batch file or two and start the publish process in the time it takes you to navigate to that directory.

Finally, the customization options available to you from within VS is too limiting. For example, if you are using VS to publish to multiple environments, how do you handle changing the parameters for each environment?

Some Notes

You can of course still run publish from VS but I don't recommend it, get out of that bad habit and start using MSBuild directly. However if you insist on using VS, if you make any changes to Customization.targets, you need to unload and reload your project in VS for those changes to be 'picked up' by VS.

Please let me know if you identify any flaws or improvements that may be made with this approach.

<Choose>
<When Condition=" '$(BuildEnvironment)' == 'DEV' ">
<PropertyGroup>
<BaseUrlPmsServices>https://ecsport3.cps.com.au/Pms</BaseUrlPmsServices&gt;
<BaseUrlEcsServices>https://ecsport3.cps.com.au/Ecs</BaseUrlEcsServices&gt;
<BaseUrlEdasServices>https://edasport.cps.com.au:1800/services</BaseUrlEdasServices&gt;
<BaseUrlHelp>http://ecstest.cps.com.au/PmsHelp</BaseUrlHelp&gt;
<PublishDir>\\172.16.101.101\ReleaseMark\$(BuildEnvironment)\</PublishDir><!-- InstallUrl>It seems that installUrl doesn't get picked up if set here, must be fed in with the msbuild command arguments.</InstallUrl -->
<!-- ApplicationVersion is set in the publishENV.bat -->
</PropertyGroup>
</When>
<When Condition=" '$(BuildEnvironment)' == 'SUB' ">
<PropertyGroup>
<BaseUrlPmsServices>https://ecspmsport1/Pms</BaseUrlPmsServices&gt;
<BaseUrlEcsServices>https://ecspmsport1/Ecs</BaseUrlEcsServices&gt;
<BaseUrlEdasServices>https://edas2-port1:1800/services</BaseUrlEdasServices&gt;
<BaseUrlHelp>http://ecspmshq/PmsHelp</BaseUrlHelp&gt;
<PublishDir>\\ecspmsport1\SmartClient\</PublishDir>
</PropertyGroup>
</When>
<When Condition=" '$(BuildEnvironment)' == 'DPS' ">
<PropertyGroup>
<BaseUrlPmsServices>https://ecspmsport2/Pms</BaseUrlPmsServices&gt;
<BaseUrlEcsServices>https://ecspmsport2/Ecs</BaseUrlEcsServices&gt;
<BaseUrlEdasServices>https://edas2-port2:1800/services</BaseUrlEdasServices&gt;
<BaseUrlHelp>http://ecspmshq/PmsHelp</BaseUrlHelp&gt;
<PublishDir>\\ecspmsport2\SmartClient\</PublishDir>
</PropertyGroup>
</When>
</Choose>

Learning PostSharp

AOP from the Trenches

Aspect Oriented Programming feels alot like applying style sheets to a web site. Changing your ‘aspects’ will change the way your program works without having to make any changes to your code.

A few months ago I saw a great demo on PostSharp by Omar Besiso and I remember thinking, must ‘check that out someday‘.

Well amazingly, someday just rolled around and I started looking at PostSharp more closely and see if it could help me. My project needs logging and exception handling to be added so we are using the enterprise library blocks and I was keen to see how PostSharp might make my life easier.

The documentation on PostSharp is good but it’s a bit thin on best practice examples and little ‘gotchas’ so this blog entry is just a little collection things I am learning along the way…note that I am completely new to Aspect Oriented programming so please correct me if I say somethings really stupid or ignorant :-)

There are also a couple of good articles on CodeProject to help you get started.

1. Restart Visual Studio

So I installed PostSharp, followed the quickstart sample exactly, compiled…didn’t seem to do anything. Ok so open up Reflector, did it actual make any changes? Nope.

After scrounging around the documentation for a while and trying various things to figure out what I was doing wrong I finally went back to the website ‘getting started’ section and in step two it clearly says ‘restart visual studio’.

Of course! Did that…all works.

And how good is this….I tweeted a hotip to restart VS after installing PS and within an hour I got message from Gael Fraiteur (the author) saying he’d raised a bug to warn users to restart VS after installing!

2. Don’t Try/Catch

These next few points all relate to handling exceptions with Aspects.

Let’s say you add this attribute to a method (and you’ve set them up properly):

[MyExceptionHandlerAspect("MyExceptionPolicy")]
public void MyMethod()
{
try
{
// exception happens here
}
catch(Exception ex) {// do something with the error
}
}

If you then do a try/catch like I have in the method then that try/catch takes over and the Aspect no longer ‘handles’ the exception. Which is good I think, you want to be able to ‘override’ what the aspect does in some instances. It feels a bit strange though, NOT wrapping a potentially naughty bit of code in a try/catch block, you have to have faith that the aspect will do its job.

NOTE: I’m not saying never use a try/catch block anymore, you will often still want to catch and specifically handle some exceptions.

3. Where Does FlowBehavior.Continue From?

I used eventArgs.FlowBehavior = FlowBehavior.Continue; and I expected the code execution to continue from (next line) where the exception occured. It didn’t, it returned to the line of code that called the method where the exception occurred. Consider the following:-

exceptionContinue

When the exception occurs in the Third method, my aspect handles it by doing whatever and then sets eventArgs.FlowBehaviour = FlowBehaviour.Continue; The result of this is execution continues in the Second method…and the Fourth method is not called.

Cool, not quite what I expected but it’s fine, the main thing is understanding how it works.

So what happens if we move that attribute?

exceptionContinue2

Well, here exception occurs in Third, but the aspect handles it in Second and so execution continues in First. Nice, just be aware of where you are putting the attribute.

We could also do this…

exceptionContinue3

Here, the exception occurs in Third and the aspect handles in Third also, so execution resumes in Two.

Note you can also put the attribute on the class, which saves you from putting it on individual methods. Seems to me that the best place to wire up the exception handlers are in the AssemblyInfo.cs files. This is what you need to add:-

[assembly:  MyExceptionHandlerAspect("MyExceptionPolicy")]

which to me is also much less confusing than attributes here and there randomly scattered through your code. Plus one of the big advantages of using PostSharp is that there is almost zero change required to existing code. So my ‘guess’ as to best practice here is to only apply an Exception Handling Aspect Attribute to individual methods when there is a very specific need to handle raised exceptions differently (i.e. use a different aspect or perhaps the same aspect with different parameters supplied – eg. in the case above I might want to use a different exception policy).

4. Continue After Exception – ‘Problem’

Just to be clear I don’t see this as a problem with PostSharp, it’s just a stumbling block I ran into.

I’m using the enterprise library, specifically for this problem I’m using the Exception Handling block. I have a policy to ‘handle’ System.Exception’s by logging them and then rethrowing an new exception that just wraps the original one.  Since all exceptions derive from System.Exception this handler will catch all exceptions except those that have their own explicitly defined handler (including the null reference exception below).

To the relevant AssemblyInfo.cs f iles I have added [assembly:  MyExceptionHandlerAspect("MyExceptionPolicy")].

Now I am also using CAB and discovered this ‘continue problem’ in a command handler.

commandHandler

I’ve added a dodgy bit of code that forces a null reference exception.

So, my PostSharp aspect looks like this

exceptionAspect

and it nicely does intercept my null reference exception but what happens when the call to HandleException is made? The enterprise library takes over and does it’s thing, logs and wraps the exception in a new exception which is returned in exceptionToThrow….great, so far so good.

The next thing that is going to happen is exceptionToThrow…will be thrown. But let’s see what the call stack looks like BEFORE it gets rethrown….

callStack1

At the top of the stack is the breakpoint I set in the OnException method in the OnExceptionAspect class. No problem, next is the OnDoSomething method where the exception occured. The next three are all CAB related (including the Infragistics line), then before that is essentially the call to Start().

So what happens is my policy causes the rethrow of the new exception, which gets thrown ‘back’ to OnExecuteAction in CAB code…which (currently) doesn’t have any PostSharp goodness to automatically wire up our exception handling policies. This means the exception will keep getting bubbled up the stack until it hits either a try/catch (that doesn’t rethrow) or an assembly with an exception aspect defined (PostSharp goodness). Let’s see what the call stack looks like after the new exception gets thrown.

callStack2

So it’s now Continuing execution from the next point that ‘handles’ the thrown exception. Problem is, that’s in the Start method and once execution continues beyond the call to base.Start then the application shutsdown (just the way a CAB app works).

Solution

Ok so I’ve gone away and thought about this for a bit and my solution is to change my policies. I now have a UI Layer Policy which never rethrows, it just logs and reports a message to the user. So all of my Modules and the main Shell use this Policy, there are other policies for other layers where required and an all purpose one that still does the log, wrap and rethrow…which eventually gets handled by some UI layer handler.

5. Lose Edit and Continue

I guess, due to the nature of how PS works (‘injecting code’, creating delegates etc Post compilation), you’ll see this kind of message popping up alot…

editAndContinue

when you try to edit code whilst debugging. So no more edit and continue if you add any Aspect Attributes to your class. What I’ve discovered so far is that if you have any methods, properties etc  in a class marked with an aspect attribute then you won’t be able to edit and continue anywhere in the class. If the class is ‘clean’ of aspects then you can edit and continue.

This is a heavy price to pay in my eyes, fine if your app is small and fast to start but my last app took 3 mins to build and compile so having to restart much more frequently when debugging would be very frustrating. Fortunately this problem is very easy to almost completely eliminate.

This straight from the documentation:

Disabling PostSharp

It can happen that you have an assembly referencing PostSharp.Public.dll, but that does not need to be processed by PostSharp. This is the case, for instance, when your assembly contains only aspects. Aspects don't need to (and can not) be themselves transformed.

The easiest way to disable PostSharp in a project is to define the compilation symbol (aka constant) SkipPostSharp.

Therefore, it is possible to have a project with many build configurations and enable PostSharp in only some of these.

So what I've done is created a DebugWithPostSharp build configuration, which is a normal debug build. Then on the Debug configuration I added the SkipPostSharp symbol to the relevant projects. The Release configuration always gets PostSharp (really important because unit tests are run against the Release build).

Summary

There are so many useful ways you could use PostSharp, just make sure you take the time to thoroughly understand how it does it's thing....experiment alot! This is just a few things I have learnt along the way, if I find anymore (and some spare time...) I'll do a part 2.

SCSF ‘Add View’ Recipe Problem

Smart Client Software Factory

We are using the SCSF on my current project and I have to say I like the idea but I hate the number of hoops you have to jump through in order to get it to work properly. One problem I recently experienced was with the Add View (with presenter)… recipe.

Add View (with presenter)…

The problem was it was not appearing in the context menu. So I looked in the Guidance Package Manager to see if I could glean any details about what I was doing wrong.

Guidance package manager

Guidance package manager

So as you can see the recipe applies to ‘any project referencing CAB libraries and the Infrastructure.Interface library.

SCSF has a solution template for creating SmartClient applications, which I had used and so I did have an Infrastructure.Interface project.

The specific ‘CAB libraries’ that the recipe cares about are:

  • Microsoft.Practices.CompositeUI.dll
  • Microsoft.Practices.ObjectBuilder.dll

So…to my project to check my references…

Project References

Project References

…hmmm, looks like all the references are good? Looks like this is one of those things that ‘should work but doesn’t’.

Debug Time

So, to get to the bottom of this, I had my solution open (VS1) and opened another instance of Visual Studio with the GuidancePackageManager.sln open (VS2). I then did an ‘attach to process’, attaching the process of the other visual studio.

attachtoprocess

attachtoprocess

Then find the right place in the GPM solution…here

breakpoint location

breakpoint location

then right click on a project in VS1, which causes the breakpoint to be hit in VS2.

The Cause of The Problem

Turns out that its happy with the CAB references but has a problem with the Infrastructure.Interface.

Why?

Because when the SCSF created the project it (quite correctly I think) created the Infrastructure.Interface project, setting the default namespace to ‘MySolution.Infrastructure.Interfaceand the assembly name to ‘MySolution.Infrastructure.Interface‘. But this means when it is comparing project references (in the ContainsReference method) if fails because it is looking for a reference to ‘Infrastructure.Interface‘ but finds ‘MyProject.Infrastructure.Interface‘.

To fix it we just went to Project Properties and in ‘Application’ set the Assembly Name back to Infrastructure.Interface. (we don’t expect to have any naming conflicts given the nature of the app).

Determine if Internet Connection Available

Smart Client

Be careful with your logic when using

NetworkInterface.GetIsNetworkAvailable()

This tells you if any network is available…which doesn’t necessarily mean that you can connect to the internet!

For example if in my app if I unplug my network cable the method returns false…until I plug in my mobile device and suddenly (and accurately) it returns true. Plugging my mobile in does not mean I have internet access BUT IT MIGHT. 

The best way to check for an internet ready connection is to make some call out to the internet and see what happens, there’s a few suggestions for which approach, I like this one:-

MARS to the Rescue

WCF Concurrency

When you create a WCF web service you most likely want it to have a ConcurrencyMode of ‘Multiple‘ so that your service will scale. Check this out if you need some convincing on this.

Here’s an error I recently ran into when multiple threads started hitting my database:

There is already an open DataReader associated with this Command which must be closed first.

I’m using enterprise libraries Data Access Block and my DB is an SQL Server 2005. For once the fix was really easy, I just had to change my connection string to include MultipleActiveResultSets=True.

That’s it!

Check out this link that helped me figure it out and this MSDN article more details.

A nice easy immediate fix for a problem I thought would require some re-engineering. Why can’t all problems be like that :-|

Silverlight Communication Exception

Cross Domain Access

I hope this article can save someone some of the pain I have just experienced trying to get my Silverlight 2 app talking to my ‘cross domain’ WCF service (that is hosted in a console app).

I’ll leave discussing why I didn’t just host my SL app with my WCF service and avoid all of hassles until the end of the article. I’m also not going to discuss how to set this up, I’ve provided links to articles that I found useful for this.

The Error

An error occurred while trying to make a request to URI ‘http://localhost:4522/MyService&#8217;. This could be due to attempting to access a service in a cross-domain way without a proper cross-domain policy in place, or a policy that is unsuitable for SOAP services. You may need to contact the owner of the service to publish a cross-domain policy file and to ensure it allows SOAP-related HTTP headers to be sent. Please see the inner exception for more details.

Existing Blog Articles

I found many useful articles, many of them with at least one little extra thing to try, these are the most useful:-

  1. Silverlight forum discussion on the cross domain policy
  2. Great step by step article to showing how to setup an SL project to consume a WCF service hosted in a Console (I thought this for sure would have all my answers)
  3. MSDN has what looks like the content needed for both the crossdomain.xml and clientaccesspolicy.xml (but it’s not quite right).
  4. Interesting discussion on crossdomain.xml and clientaccesspolicy.xml.
  5. StackOverflow thread.
  6. Cross-domain Policy File Specification. This is what eventually led to me trying something that finally it all working!

All of this (and a number of others I looked at) helped, they really are great articles and I could see comments at the bottom saying things like “thanks got it working now!”. Problem was I had very closely checked and rechecked what I had done vs what was in these blogs and still I kept getting the error!

The Solution

After many hours of trying many different things I came across the  and tried an extra little line and voila…working service! That’s a great feeling isn’t it…when you’ve been trying to find a solution to a problem for hours…and hours…you know there must be an answer but everything you try should work but dammit it doesn’t…and then…suddenly…you tick some obscure buried box somewhere and the universe is back to the way it should be…

anyway I digress…this is what MSDN says you should put in your crossdomain.xml file

<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
  <allow-http-request-headers-from domain="*" headers="*"/>
</cross-domain-policy>

This is what actually works!

<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
<allow-access-from domain="*" />
<allow-http-request-headers-from domain="*" headers="SOAPAction" />
</cross-domain-policy>

I've highlight the important line. You'll notice that the MSDN sample has headers="*",  this simply does not work. In fact if I add the extra line that makes it work and headers="*" is still in the first line, then everything still fails. So delete headers="*" and add the new line.

Another thing to note, I noticed amongst the articles posted on this subject that if you have a clientaccesspolicy.xml file then you don't need a crossdomain.xml file. Maybe this is true with their setup but I have found that you must have a crossdomain.xml file, in fact after a bit more trial and error I have come to the conclusion that the clientaccesspolicy.xml just does NOT WORK! At least for me. If my SL app finds it then I get the error...no matter what I put in there. Only when my service does NOT return it but DOES return a crossdomain.xml file with the correct format above does it work.

Maybe this was all a peculiarity of hosting the WCF service inside a console app? Not sure. Don't care at this point, the thing finally works...yay!

Do I Need a File

You can choose to create the required xml in code or you can have the physical file, your choice. Most of the examples just create it in code. It's not the existence of the file that matters, just the contents and the web GET request must be able to retrieve the content.

By the way, all examples I have seen (including mine) leave your service completely unsecured. I strongly recommend learning how to set these policy files up properly so that your service isn't nakedly exposed to the outside world.

What Didn't Help

In case you have some other problem, these are the things I can say didn't make a difference. Once I got it working I tried with and without these things and my cross domain connection still worked.

1. Does setting the ContentType help?

WebOperationContext.Current.OutgoingResponse.ContentType = "application/xml";

Nope doesn't matter.

2. Some blog samples show a return type of 'Message' and others a return type of 'Stream' for the method that this attribute goes on:-

[WebGet(UriTemplate = "ClientAccessPolicy.xml", BodyStyle = WebMessageBodyStyle.Bare)]

Does the return type matter? Nope doesn't matter (well I only tried these two types, I guess it should be one of these)

3. I read you should decorate your services with this attribute...is it needed?

[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]

Nope, didn't help. (note that it didn't help with THIS problem, I'm sure there is some good reason for why you would use it)

So Why Bother With Cross Domain?

  1. In an enterprise environment it is very likely that you will need to call a number of different services. Sure you could have one WCF service that is just for your SL app that then goes off and talks to all of the disparate services for the SL app but that just doesn't seem right to me. (just an opinion and hey in some cases it probably is appropriate...)
  2. Isn't it all about separation of concerns? When I'm working on server side code I only want server side projects in my solution and vice versa for client solutions. This keeps the number of projects in my solution down...thereby keeping Visual Studio (and resharper) at least a little bit responsive.
  3. When the server is working I just want it running. I don't want to have to compile and start the server every time I want to debug something in my client code.

Hmmm, I'm sure there's other reasons but I can't think now given it's 3am :-(

Anyway I hope this helps someone save some time :-)

Studio Version Selector Failure

The Questions

Are you clicking on your .sln file and nothing is happening?

Is it using the Visual Studio Version Selector (VSVS) to try to open your solution??

Do you only have ONE VERSION of visual studio on your machine???

Are you thinking “this VSVS is a piece of rubbish! How can it fail to find and use my ONE installed version!!”????

Well worry no more, the solution is simple (well, assuming you have the same problem as I did).

The Fix

  1. Open your .sln in wordpad
  2. Remove the blank line(s) from the top of the file
  3. Save
  4. Done!

It seems that VSVS is not capable of searching beyond the first line of the file for the version number. Is it just me or that lame?

Follow

Get every new post delivered to your Inbox.