Notes from Daily Encounters with Technology RSS 2.0
 
# Sunday, January 08, 2012

Web.config transformations are a great but often overlooked feature introduced with ASP.NET 4.0. They provide a simple way to define a different configuration for Debug and Release builds of your project by only specifying the differences (typically only connection strings and similar settings) in a separate transformation file while keeping the core of the configuration file common and consequentially making it easier to manage.

Unfortunately files aren’t transformed until the web deployment package is created, i.e. they aren’t part of the core build process. This makes the transformations more difficult to use in some scenarios such as having a different configuration file for automated testing as a part of the build process.

Since the transformation is done by the TransformXml MSBuild task in Microsoft.Web.Publishing.Tasks.dll assembly there is a way to make this work by modifying the project file manually, though. Here is a snippet that I added to my project file (line break in the AssemblyFile added for readability only):

<UsingTask TaskName="TransformXml" 
           AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\
                         v10.0\Web\Microsoft.Web.Publishing.Tasks.dll" />
<Target Name="AfterBuild">
    <MakeDir Directories="obj\$(Configuration)" 
             Condition="!Exists('obj\$(Configuration)')" />
    <TransformXml Source="Web.Config" 
                  Transform="Web.$(Configuration).config" 
                  Destination="obj\$(Configuration)\Web.config" 
                  StackTrace="true" 
                  Condition="Exists('Web.$(Configuration).config')" />
</Target>

As you can see the transformed configuration file is put inside the obj folder from where I copy it to the desired final location before running the tests. I find this a suitable spot for it unless you are precompiling views in your ASP.NET MVC project. A web.config file anywhere in obj folder brakes the build so you’ll have to put the file elsewhere or make sure you delete it before precompiling the views.

If you want to make this work on your build server without having Visual Studio installed on it, there is one more step remaining. The above mentioned assembly is not installed with .NET SDK meaning that you have to copy it there from your development machine. The file is located in the MSBuild extension folder, i.e. “C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v10.0\Web\” by default.

Transformation files displayed under the original fileThis takes care of transforming web.config files during build. How about transforming app.config files and even other XML files in your projects? I guess it would be possible to use the same MSBuild task on them but no Visual Studio support for transforming those files would mean even more tempering with project files to make transformation files appear under the file they are used to transform.

This is where SlowCheetah – XML Transforms Visual Studio extension can help. After installing it you can define transformations for app.config the same way you are already doing it with web.config files. The transformation is part of the build process in this case, i.e. the transformed file is put in its usual spot in the build output folder (usually bin) instead of the original one. It couldn’t get any simpler.

As an added bonus the extension features support for previewing the results of the transformation: after right clicking the transformation file and selecting the Preview Transform command a diff window will open graphically showing the differences between the original and the transformed file. Of course this works with web.config transformations as well making the debugging of transformations much simpler. A good reason in itself to install this extension.

To avoid failed builds on your build server as well as with the other members of your team not having this extension installed it’s best that you copy the SlowCheetah MSBuild targets and the corresponding assembly containing the tasks to your solution directory and put it in source control. In this case you’ll again have to modify the project file to set the new path. Just search for the SlowCheetahTargets property definition and modify the path accordingly (line breaks added for readability):

<PropertyGroup>
    <SlowCheetahTargets Condition=" '$(SlowCheetahTargets)'=='' ">
        ..\_References\SlowCheetah\SlowCheetah.Transforms.targets
    </SlowCheetahTargets>
</PropertyGroup>

Are there any ways to make your life simpler by using configuration transformations in your projects?

Sunday, January 08, 2012 12:34:56 PM (Central European Standard Time, UTC+01:00)  #    Comments [0] - Trackback
Development | .NET | ASP.NET | Software | VisualStudio
# Monday, December 26, 2011

DateTime can be a tricky data type to deal with. Not only is there daylight saving time and different time zones to keep in mind but also the range and precision can vary in different systems. You are probably already aware of some differences between .NET framework’s DateTime structure in Transact-SQL’s datetime data type.

Most notable is certainly a different minimum value that can be expressed:

  • In .NET framework all values between January 1st 1 and December 31st 9999 are supported.
  • In Transact-SQL only values between January 1st 1753 and December 31st 9999 are supported.

This usually shouldn’t be a problem unless you are working with historic data. Setting proper minimum value in the user interface is not be a bad idea nevertheless.

You might not be aware of the difference in precision between these two data types, though. In some edge cases this can cause strange and unpredictable behavior. Let’s take a look at the following example (based on an issue that had me mystified for some time):

using (var context = new TestEntities())
{
    var task = context.Tasks.Single(t => t.Id == taskId);
    task.CompletedAt = DateTime.Now;
    timestamp = task.CompletedAt.Value;
    context.SaveChanges();
}

using (var context = new TestEntities())
{
    var task = context.Tasks.Single(t => t.Id == taskId);
    Assert.GreaterOrEqual(timestamp, task.CompletedAt);
}

The assertion in the above code will occasionally fail with a message similar to this one:

SampleTest has failed:
  Expected: greater than or equal to 2011-12-26 19:04:28.313
  But was:  2011-12-26 19:04:28.312

If you’re not familiar with entity framework, here’s what’s going on:

  • In the first code block a DateTime value is stored to the database.
  • In the second code block that same value is reloaded from the database.
  • The value from the database is compared with the one stored in a local variable the whole time.

The strange behavior is caused by the fact that milliseconds get rounded in the database: to increments of .000, .003, or .007 seconds, as it is stated in the documentation. The DateTime value can therefore be different when reloaded from the database, hence the occasional failed assertion. While the problem might be fairly obvious in the simplified example above, it can be much more difficult to pinpoint in a larger chunk of code where there could be other reasons for the values to differ. Even more so if you’re not even aware of the rounding.

Knowing this might save you a couple of hours once.

Monday, December 26, 2011 7:28:18 PM (Central European Standard Time, UTC+01:00)  #    Comments [0] - Trackback
Development | .NET | SQL
# Monday, December 19, 2011

In a previous post I addressed the issue of using HTTP module based authentication in WCF. The presented solution worked in most cases but failed completely with Windows authentication. In this post I’ll describe the necessary changes to make this work as well.

Let’s first see what goes wrong with the existing solution and why. To configure WCF for Windows authentication, the following changes are required in web.config:

<system.serviceModel>
    <!-- ... -->
    <bindings>
        <basicHttpBinding>
            <binding name="HttpWindowsBinding" 
                     maxReceivedMessageSize="2147483647">
                <security mode="TransportCredentialOnly">
                    <transport clientCredentialType="Windows" />
                </security>
            </binding>
        </basicHttpBinding>
    </bindings>
    <services>
        <service name="WcfAuthentication.Service">
            <endpoint address="windows"
                      binding="basicHttpBinding"
                      bindingConfiguration="HttpWindowsBinding"
                      contract="WcfAuthentication.IService" />
        </service>
    </services>
</system.serviceModel>

Of course the settings have to be matched in IIS: Windows authentication should be enabled for the application while anonymous authentication should be disabled, as well as all the other types of authentication.

After setting all this up any calls to our service will throw a MessageSecurityException: "The HTTP request is unauthorized with client authentication scheme 'Negotiate'. The authentication header received from the server was 'Negotiate,NTLM'." If you try searching the web for solutions, you’ll notice the same error pops up in many different situations not related to our case. So what’s going on here?

The problem is being caused by the following method in HttpAuthenticationModule:

void context_AuthenticateRequest(object sender, EventArgs e)
{
    HttpContext.Current.User = ProcessAuthentication();
}

Setting the user in the current HttpContext to a custom IPrincipal implementation confuses WCF which expects a WindowsPrincipal as configured. The only way to make it work is to pass through the original user information in this case:

void context_AuthenticateRequest(object sender, EventArgs e)
{
    if (!(HttpContext.Current.User is WindowsPrincipal) && 
        HttpContext.Current.Request.AppRelativeCurrentExecutionFilePath.EndsWith(".svc"))
        HttpContext.Current.User = ProcessAuthentication();
}

The extension based filtering is there so that the authentication will still work for the rest of our web application. This change alone is not enough, of course. We still to need the authentication somewhere for the WCF case. HttpContextAuthorizationPolicy is the right spot for it. Evaluate method should be modified as follows:

public bool Evaluate(EvaluationContext evaluationContext, ref object state)
{
    HttpContext context = HttpContext.Current;

    if (context != null)
    {
        if (context.User is WindowsPrincipal)
        {
            IPrincipal principal = HttpAuthenticationModule.ProcessAuthentication();
            evaluationContext.Properties["Principal"] = principal;
            evaluationContext.Properties["Identities"] = new List<IIdentity> { principal.Identity };
        }
        else
        {
            evaluationContext.Properties["Principal"] = context.User;
            evaluationContext.Properties["Identities"] = new List<IIdentity> { context.User.Identity };
        }
    }

    return true;
}

Keep in mind that calling a static method in HttpAuthenticationModule to authenticate the user is just a shortcut to make this sample work and is not suggested practice. In production code you’ll want to have your authentication logic implemented somewhere in the business layer and call it from both HttpAuthenticationModule and HttpContextAuthorizationPolicy.

Monday, December 19, 2011 9:12:16 PM (Central European Standard Time, UTC+01:00)  #    Comments [0] - Trackback
Development | .NET | ASP.NET | WCF
# Monday, December 12, 2011

WCF has great built-in support for most types of authentication so there aren’t many good reasons to use HTTP module based authentication with it. Having an existing ASP.NET application already using such authentication certainly is one of them. Finding resources on how to do it might be a challenge though. I managed to stumble upon an article by Microsoft patterns & practices team which helped a lot. In a way this post is its abridged and more practical version.

From here on I assume you already have an IHttpModule in your application (ProcessAuthentication() being the method implementing the actual authentication of the user):

public class HttpAuthenticationModule : IHttpModule
{
    public void Dispose()
    { }

    public void Init(HttpApplication context)
    {
        context.AuthenticateRequest += context_AuthenticateRequest;
    }

    void context_AuthenticateRequest(object sender, EventArgs e)
    {
        HttpContext.Current.User = ProcessAuthentication();
    }

    private static IPrincipal ProcessAuthentication()
    {
        // implement your authentication here
        IIdentity identity = new GenericIdentity("Authenticated User");
        return new GenericPrincipal(identity), null);
    }
}

The module should also already be registered in web.config:

<system.web>
    <!-- ... -->
    <httpModules>
        <add name="HttpAuthenticationModule" 
             type="WcfAuthentication.HttpAuthenticationModule"/>
    </httpModules>
</system.web>

The goal is of course getting access to the authenticated user (i.e. IPrincipal instance) in WCF service through ServiceSecurityContext. The following test method is a great way for testing that:
public string GetUser()
{
    if (ServiceSecurityContext.Current != null)
        return ServiceSecurityContext.Current.PrimaryIdentity.Name;
    else
        return null;
}

IAuthorizationPolicy is the interface to implement custom authorization in WCF with. In our case the authenticated user can be accessed through current HttpContext:

public class HttpContextAuthorizationPolicy : IAuthorizationPolicy
{
    public bool Evaluate(EvaluationContext evaluationContext, ref object state)
    {
        HttpContext context = HttpContext.Current;

        if (context != null)
        {
            evaluationContext.Properties["Principal"] = context.User;
            evaluationContext.Properties["Identities"] = new List<IIdentity>() { context.User.Identity };
        }

        return true;
    }

    public System.IdentityModel.Claims.ClaimSet Issuer
    {
        get { return ClaimSet.System; }
    }

    public string Id
    {
        get { return "HttpContextAuthorizationPolicy"; }
    }
}

Of course the class should be registered in web.config so that our service will use it:

<system.serviceModel>
    <!-- ... -->
    <behaviors>
        <serviceBehaviors>
            <behavior>
                <!-- ... -->
                <serviceAuthorization>
                    <authorizationPolicies>
                        <add policyType="
                             WcfAuthentication.HttpContextAuthorizationPolicy, 
                             WcfAuthentication, Version=1.0.0.0, 
                             Culture=neutral, PublicKeyToken=null"/>
                    </authorizationPolicies>
                </serviceAuthorization>
            </behavior>
        </serviceBehaviors>
    </behaviors>
</system.serviceModel>

There is still one thing missing. If you try out the above code, you will realize that HttpContext.Current is always null even if authorization in our HTTP module was successful. To get access to it you need to enable ASP.NET compatibility:

<system.serviceModel>
    <!-- ... -->
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" 
                               aspNetCompatibilityEnabled="true"/>
</system.serviceModel>

To make your WCF service work in this mode you need decorate it with AspNetCompatibilityRequirementsAttribute:

[AspNetCompatibilityRequirements(RequirementsMode = 
    AspNetCompatibilityRequirementsMode.Allowed)]
public class Service : IService
{
    // ...
}

Finally, we’re done. If you’ve implemented all of the above correctly, our test method GetUser() should return the user who was authenticated in the HTTP module. Unless you’re trying to use Windows authentication which still doesn’t work in this setup. That’s already a subject for another post, though.

Monday, December 12, 2011 9:29:48 PM (Central European Standard Time, UTC+01:00)  #    Comments [0] - Trackback
Development | .NET | ASP.NET | WCF
# Thursday, December 01, 2011

DefaultModelBinder is an essential piece of ASP.NET MVC framework which makes writing strongly typed actions really simple. In spite of its strengths (or maybe because of them) it can still introduce hard to solve problems in your code. Take a look at the following example, a simplification of the problem I was confronted with today:

public class DocumentVersion
{
    public int Id { get; set; }
    public int Version { get; set; }
    public string Name { get; set; }
}

public class DocumentController : Controller
{
    public ActionResult New()
    {
        return View();
    }

    public ActionResult Save(DocumentVersion version)
    {
        if (ModelState.IsValid)
        {
            // save data
            return View("Confirm");
        }
        return View("New");
    }
}

Assuming all DocumentVersion properties are submitted and valid Save action should return Confirm view, right? Wrong! Try it out and you’ll get a validation error on Version property. Taking a closer look it turns out ModelState["Version"].Errors[0].Exception contains an InvalidOperationException: "The parameter conversion from type 'System.String' to type 'MvcApplication1.Models.DocumentVersion' failed because no type converter can convert between these types." Of course there’s no String to DocumentVersion converter. Though, Version property is an int. Why does it want to convert it to a DocumentVersion?

I soon started running out of ideas and fortunately enough I quickly decided to enable .NET Framework source stepping. A few moments later I reached the following piece of code in DefaultModelBinder and suddenly it became obvious what was happening:

if (!String.IsNullOrEmpty(bindingContext.ModelName)
        && !bindingContext.ValueProvider.ContainsPrefix(bindingContext.ModelName)) {
    // We couldn't find any entry that began with the prefix. If this is the top-level element, fall back
    // to the empty prefix.
    if (bindingContext.FallbackToEmptyPrefix) { 
        bindingContext = new ModelBindingContext() {
            ModelMetadata = bindingContext.ModelMetadata, 
            ModelState = bindingContext.ModelState, 
            PropertyFilter = bindingContext.PropertyFilter,
            ValueProvider = bindingContext.ValueProvider 
        };
        performedFallback = true;
    }
    else { 
        return null;
    } 
} 

// Simple model = int, string, etc.; determined by calling TypeConverter.CanConvertFrom(typeof(string)) 
// or by seeing if a value in the request exactly matches the name of the model we're binding.
// Complex type = everything else.
if (!performedFallback) {
    bool performRequestValidation = ShouldPerformRequestValidation(controllerContext, bindingContext); 
    ValueProviderResult vpResult = 
        bindingContext.UnvalidatedValueProvider
                      .GetValue(bindingContext.ModelName, skipValidation: !performRequestValidation);
    if (vpResult != null) { 
        return BindSimpleModel(controllerContext, bindingContext, vpResult); 
    }
} 

Notice the call to bindingContext.ValueProvider.ContainsPrefix(bindingContext.ModelName) at the top and read the comment above the bottom block of the code. It turns out that in my sample ModelName Was "version" just like one of the DocumentVersion properties therefore DefaultModelBinder decided to use simple model binding which failed because of a missing converter as it was also clearly stated in the exception. You might be wondering where ModelName came from. It’s the name of the action method parameter. Fixing the code was simple now – rename the parameter and the code starts working as expected:

public ActionResult Save(DocumentVersion documentVersion)
{
    if (ModelState.IsValid)
    {
        // save data
        return View("Confirm");
    }
    return View("New");
}

Lesson of the day? Be aware of conventions and make sure parameter names don’t match any of the property names if you are using complex models.

Thursday, December 01, 2011 9:42:37 PM (Central European Standard Time, UTC+01:00)  #    Comments [0] - Trackback
Development | ASP.NET MVC
Sponsored Ads

About Me
Twitter
Support charity with the Humble Bundle Mojam livestream event! http://t.co/9c91hoB9 via @humble 4 days ago
Damir's Corner: Peculiarities of Subversion Path Based Authorization http://t.co/YTFpisrY 4 days ago
These 50 Photos Will Blow you Away http://t.co/HeD6HWit via @photoshoptalent 4 days ago
Another good reason for everyone to rather use Virtual CloneDrive instead http://t.co/ecLmrjZb 9 days ago
The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

All Content © 2012, Damir Arh, M. Sc. Send mail to the author(s) - Privacy Policy - Sign In
Based on DasBlog theme 'Business' created by Christoph De Baene (delarou)
Social Network Icon Pack by Komodo Media, Rogie King is licensed under a Creative Commons Attribution-Share Alike 3.0 Unported License.