среда, 17 марта 2010 г.

Hosting WCF in IIS 7.5: HTTP Error 404.17 - Not Found

Another quick entry. I’m hosting WCF service in IIS 7.5 (Windows 7 x32) and getting the following error:

HTTP Error 404.17 - Not Found
The requested content appears to be script and will not be served by the static file handler.

Found solution in this thread: it looks like the script maps for the .svc extension are not registered. To register the script maps run the following command:

%windir%\Microsoft.NET\Framework\v3.0\Windows Communication Foundation\ServiceModelReg.exe -i

вторник, 9 марта 2010 г.

What I really hate about Silverlight

Silverlight is feature incomplete, but I can live with what’s available. Some features are incompatible with WPF counterparts, but I can workaround incompatibilities. What I really hate about Silverlight is the way it reports runtime errors.

Example. Debugging custom templated control I got the following message:

Error: Unhandled Error in Silverlight Application
Code: 2012   
Category: ParserError      
Message: Unknown attribute Text on element TextBlock.    
File:     
Line: 2    
Position: 41

The message is confusing to say the least (unless I miss something, Text attribute is perfectly valid on a TextBlock element). And I had to use trial and error method just to find out silly mistake: there was a TemplateBinding to CLR-property in a control template. I should have declared that property as DependencyProperty. What a waste of time :(

пятница, 26 февраля 2010 г.

WCF services asynchronously in Silverlight without generated proxy

Just found a very interesting post by Ayende Rahien on using WCF services asynchronously without generated proxies. And Mark J. Miller in his blog shows how to use the approach in Silverlight application.

воскресенье, 14 февраля 2010 г.

Binding to custom attached property

This is a quick post on an interesting binding issue I came across the other day.

In most cases it is possible to omit the name of the Path parameter in the binding markup. But if you binding to a custom attached property, you may encounter a problem. See the code snippet below:

<Window
x:Class="BindingIssueDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:BindingIssueDemo"
Title="MainWindow" Height="350" Width="525">
<DockPanel>
<TextBlock DockPanel.Dock="Top"
Text="{Binding (DockPanel.Dock), RelativeSource={RelativeSource Self}}" />
<TextBlock local:CustomProperties.Description="Custom attached property"
Text="{Binding (local:CustomProperties.Description), RelativeSource={RelativeSource Self}}" />
</DockPanel>
</Window>

When you run the program, only the first TextBlock has text, the second one remains empty. And debugger output window prints the following error message:
System.Windows.Data Error: 39 : BindingExpression path error: '(local:CustomProperties.Description)' property not found on 'object' ''TextBlock' (Name='')'. BindingExpression:Path=(local:CustomProperties.Description); DataItem='TextBlock' (Name=''); target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String')
I Googled a bit and found that the problem occurs when binding to attached properties in a non-default XML namespace. To workaround the issue you have to explicitly specify Path= in binding markup:
 
<TextBlock local:CustomProperties.Description="Custom attached property"
Text="{Binding Path=(local:CustomProperties.Description), RelativeSource={RelativeSource Self}}" />
 
Seems like this issue has been fixed in Visual Studio 2010 RC / .NET 4.0.

воскресенье, 7 февраля 2010 г.

DXPrinting: using DataTemplateSelector with SimpleLink

Printing data with a SimpleLink is straightforward: define a DataTemplate that represents a data item layout, specify the number of items and call the CreateDocument method.

But what if your data consists of objects of different types? How do you print them when each type has its own layout? This is where DataTemplateSelector comes to help.

Consider that we have a collection of CalendarEntry objects:

CalendarEntryClassHierarchy
Let's start with creating a DataTemplate for each calendar entry type. To keep things simple, I'm using a very simple layout:

<DataTemplate x:Key="anniversary">
  <Border BorderBrush="Black" BorderThickness="1" CornerRadius="5" Margin="0,0,0,5" Background="LightBlue">
    <StackPanel Margin="5">
      <TextBlock Text="{Binding Date, StringFormat='Date: {0}'}" />
      <TextBlock Text="{Binding Occasion, StringFormat='Occasion: {0}'}" />
    </StackPanel>
  </Border>
</DataTemplate>
<DataTemplate x:Key="todo">
  <Border BorderBrush="Black" BorderThickness="1" CornerRadius="0" Margin="0,0,0,5" Background="LightGray">
    <StackPanel Margin="5">
      <TextBlock Text="{Binding DueDate, StringFormat='Due Date: {0}'}" />
      <TextBlock Text="{Binding Subject, StringFormat='Subject: {0}'}" />
    </StackPanel>
  </Border>
</DataTemplate>
<DataTemplate x:Key="meeting">
  <Border BorderBrush="Black" BorderThickness="1" CornerRadius="0" Margin="0,0,0,5" Background="LightGreen">
    <StackPanel Margin="5">
      <TextBlock Text="{Binding Subject, StringFormat='Subject: {0}'}" />
      <TextBlock Text="{Binding Location, StringFormat='Location: {0}'}" />
      <TextBlock Text="{Binding Start, StringFormat='Start: {0}'}" />
      <TextBlock Text="{Binding End, StringFormat='End: {0}'}" />
    </StackPanel>
  </Border>
</DataTemplate>

Now when we have our data templates, let's create a data template selector. Instead of writing an ad-hoc selector simply for this example, I've built a reusable DetailTemplateSelector class. It provides the Type and DataTemplate properties, which allows you to configure it as follows:

<local:DetailTemplateSelector x:Key="calendarEntryTemplateSelector">
  <local:DetailTemplateSelector.Templates>
    <DataTemplate x:Key="{x:Type local:ToDoNote}">
      <!-- ToDoNote template definition -->
    </DataTemplate>
    <DataTemplate x:Key="{x:Type local:Anniversary}">
      <!-- Anniversary template definition -->
    </DataTemplate>
    <DataTemplate x:Key="{x:Type local:Meeting}">
      <!-- Meeting template definition -->
    </DataTemplate>
  </local:DetailTemplateSelector.Templates>
</local:DetailTemplateSelector>

And now the final trick: the SimpleLink class doesn't have any property to set a data template selector. We use a workaround: our detail template is a ContentPresenter and its ContentTemplateSelector property is set to the DetailTemplateSelector object:

<DataTemplate x:Key="calendarEntry">
  <ContentPresenter ContentTemplateSelector="{StaticResource calendarEntryTemplateSelector}" />
</DataTemplate>

Now we can use a link to build a document and show its print preview:

UsingDataTemplateSelectorWithSimpleLink

Easy enough, isn’t it?

среда, 20 января 2010 г.

Получаем PropertyDescriptor: использование выражений вместо строк с именами свойств

Есть у нас несколько тестов, в которых создаются PropertyDescriptor для свойств объекта. Выглядело это так:

   1: [Test]
   2: public void SomeTest() {
   3:     FooBar foo = new FooBar() { SimpleString };
   4:     PropertyDescriptor property = TypeDescriptor.GetProperties(foo)["SimpleString"];
   5:     // code continues ...
   6: }

Кодировать имена свойств в строковые константы - как-то не айс. Вдохновленный использованием expressions в moq, asp.net mvc и других фреймворках, я добавил вспомогательный метод FooBar.GetProperty:

   1: class FooBar {
   2:     public static PropertyDescriptor GetProperty<T>(Expression<Func<T>> propertyExpression) {
   3:             MemberExpression body = (MemberExpression)propertyExpression.Body;
   4:             PropertyDescriptor property = TypeDescriptor.GetProperties(body.Member.DeclaringType)[body.Member.Name];
   5:             Debug.Assert(property != null);
   6:             return property;
   7:     }
   8: }

Теперь в коде тестов можно избавиться от строковых констант с именами свойств, заменив их на выражения. Новый код показан ниже:

   1: [Test]
   2: public void SomeTest() {
   3:     FooBar foo = new FooBar() { SimpleString };
   4:     PropertyDescriptor property = FooBar.GetProperty(() => foo.SimpleString);
   5:     // code continues ...
   6: }

В плюс: подсказки Intellisense при наборе, более тесная интеграция с инструментами рефакторинга (так, Find All References теперь выдает не пустой результат для свойств FooBar).

Random thoughts, ideas and questions on .NET development

Постоянные читатели