Monday, January 18, 2010

Wow, so many posts in so few days.... someone should give me a medal.

After a plague of errors when trying to deploy some IIS7 hosted WCF services to a machine, and then using VS2008 from my local machine to create a ServiceReference, i thought i should list some of the issues and what fixed them. Any issues worth mentioning will get their own blog posts, so they will be short and sharp.

The document at the url http://192.168.0.999/ProjectServices/WebServices/MyWCFService.svc was not recognized as a known document type.
The error message from each known type may help you fix the problem:
- Report from 'DISCO Document' is 'There was an error downloading 'http://server2008.workflow.local/ProjectServices/WebServices/MyWCFService.svc?disco'.'.
- The request failed with HTTP status 502: Proxy Error ( Host was not found ).
- Report from 'WSDL Document' is 'The document format is not recognized (the content type is 'text/html; charset=UTF-8').'.
- Report from 'http://192.168.0.999/ProjectServices/WebServices/MyWCFService.svc' is 'The document format is not recognized (the content type is 'text/html; charset=UTF-8').'.
- Report from 'XML Schema' is 'The document format is not recognized (the content type is 'text/html; charset=UTF-8').'.
Metadata contains a reference that cannot be resolved: 'http://192.168.0.999/ProjectServices/WebServices/MyWCFService.svc'.
Content Type application/soap+xml; charset=utf-8 was not supported by service http://192.168.0.999/ProjectServices/WebServices/MyWCFService.svc. The client and service bindings may be mismatched.
The remote server returned an error: (415) Cannot process the message because the content type 'application/soap+xml; charset=utf-8' was not the expected type 'text/xml; charset=utf-8'..
If the service is defined in the current solution, try building the solution and adding the service reference again.


It turns out i was missing a mex entry from my service endpoint addresses in my web.config. As soon as i added it:

<services>
  <service behaviorConfiguration="BaseServiceBehavior" name="MyProject.Web.Services.MyWCFService">
    <endpoint binding="basicHttpBinding" bindingConfiguration="MyWCFService" contract="MyProject.Web.Services.IMyWCFService" />
    <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
  </service>
</services>


the Add Service Reference started working. W00t.

*note for those who spotted the invalid url: as usual, identities have been changed to protect the innocent.

Tuesday, January 12, 2010

Better file searching in Windows 7

Wow, i just found another cool feature in Windows 7 - a nice way to do file searching.

I had tried to run a SourceSafe history report to find what files i had changed on a specific project, and of course SourceSafe was being its usual wanky horrendous self and the report was producing nothing. So i move to plan B - use a file search on my local hard drive, and order by date modified. Then i noticed that Windows 7 now allows you to search by a date range:





The syntax is

datemodified:<start date> .. <end date>

you can type this directly in to the search box, the date formats are in the UI locale you are running as. You can also use your mousey mouse to select the date range from the dropdown date selector, but personally i find it faster and more accurate to just type it in.

Quick example time: what did i add to my Zune playlist in the last few months of last year? (did you think i was gonna show a pic of all the code i wrote - hell no!!)


Monday, January 11, 2010

Dynamic ControlTemplate in Silverlight

I have a Silverlight 3 application that uses a grid from DevExpress. I needed to extend the standard AgDataGridColumn so that i could show images, those images being representations of an enumeration.

To achieve this is simple enough - just override the ControlTemplate that is assigned to the DisplayTemplate property of the column. Doing this declaratively (in XAML) is pretty damn simple. But i wasn't doing it that way - as i am using a factory pattern for creating the columns from some agnostic descriptors, i needed to locate, load and assign the ControlTemplate programmatically.

The extended grid column sits in a second assembly. As i had created several templated controls in this controls assembly, the project templates had already created a ResourceDictionary called generic.xaml in the Themes folder, so i intended to use this file to define the ControlTemplate and then just load it in code, using a line of code similar to


ControlTemplate ct = Application.Current.Resources["MyImageColumnTemplate"] as ControlTemplate;

Unfortunately, this didn't work, Application.Current.Resources had no idea about my ControlTemplate. Then i realised that because it was defined in a ResourceDictionary, i needed to load that ResourceDictionary and merge it with the resources associated with the current application. To do that is pretty simple:

ResourceDictionary dict = new ResourceDictionary();
dict.Source = new Uri("path to resource dictionary", UriKind.Absolute);

Application.Current.Resources.MergedDictionaries.Add(dict);


But of course nothing is that simple, right? I found half a dozen blog or forum postings that indicated all i would have to use for my URI was this:

Uri uri = new Uri("pack://application:,,,/MySilverlightControls;component/themes/generic.xaml", UriKind.Absolute);

The scheme is correct, the assembly name is correct, the path is correct, what could go wrong? Well, first i received an error about there being no port number specified:


UriFormatException was unhandled by user code

Invalid URI: A port was expected because of there is a colon (':') present but the port could not be parsed.

A little bit more googlebinging showed me that i probably needed to register the pack scheme – i thought it would already be registered (especially as the Loaded event for several Silverlight components had been fired) but it wasn't. OK, another half step forward:

if (!UriParser.IsKnownScheme("pack"))

UriParser.Register(newGenericUriParser(GenericUriParserOptions.GenericAuthority), "pack", -1);


Once i dropped that bit of code in an appropriate place, that error went away. But then i started to be plagued with vague COM errors depending on how i tried to declare the URIs.


dict.Source = new Uri("/themes/generic.xaml", UriKind.Relative);


dict.Source = new Uri("./../../themes/generic.xaml", UriKind.Relative);


dict.Source = new Uri("../../themes/generic.xaml", UriKind.Relative);

all produced the error


Error HRESULT E_FAIL has been returned from a call to a COM component.


at MS.Internal.XcpImports.CheckHResult(UInt32 hr)


at MS.Internal.XcpImports.SetValue(INativeCoreTypeWrapper obj, DependencyProperty property, String s)


at etc, etc...



dict.Source = new Uri("pack://application:,,,/themes/generic.xaml", UriKind.Absolute);


dict.Source = new Uri("pack://application:,,,/MySilverlightControls;component/themes/generic.xaml", UriKind.Absolute);

both produced the error


Exception from HRESULT: 0x80072EE5

which effectively means "Invalid URI".

So i did what any engineer or scientist should do – remove every variable from the equation until you are left with just the single problematic item, and then try and isolate the problem. I created a new ResourceDictionary
(called Dictionary1.xaml) under the Themes folder, put the MyImageColumnTemplate XAML in there, and went back through my seven different ways of specifying the URI for the ResourceDictionary. Suddenly i had success! This ended up being the code that worked:

XAML:


<ControlTemplate x:Name="MyImageColumnTemplate" >

<Grid MaxHeight="20" MaxWidth="20">

<Grid.Resources>

<localGrid:EnumColumnImageConverter x:Key="ImageContentConverter"/>

</Grid.Resources>

<Image Source="{Binding EditValue, Converter={StaticResource ImageContentConverter}}" />

</Grid>

</ControlTemplate>


C#:

Uri uri = new Uri("/MySilverlightControls;component/themes/Dictionary1.xaml", UriKind.Relative);

ResourceDictionary dict = new ResourceDictionary();

dict.Source = uri;

Application.Current.Resources.MergedDictionaries.Add(dict);

ControlTemplate ct = (ControlTemplate)Application.Current.Resources["MyImageColumnTemplate"];

this.DisplayTemplate = ct;

That URI also worked when i pointed it at generic.xaml. All the other attempted URIs look correct, but none of them would work. Now i had a custom image column that used my custom ControlTemplate, which in turn used my Converter to translate an enumeration into the appropriate image (that image was also extracted from a resource file.... but i had no issue with that!).


Wow, this post was a bit long but i tried my best to keep it simple, and i hope it helps someone out there.