Tuesday, May 1, 2012

Unity, Injection and the surprise InvalidCastException of System.Type

Chances are if you have run into this message you might be trying to inject your constructor, property or method with a type as a type. The reason? Default behavior of unity is to resolve a type to an instance and inject it for you. This feature applies to all injection and is not terribly clear in the Unity documentation. It also comes up quite frequently on the stackoverflow unity channel.
An example of the full error message in all it's glory:
Resolution of the dependency failed, type = \"MyNamespace.IMyInteface\", name = \"(none)\".\r\nException occurred while: 
Resolving parameter \"myConstructorParameter\" of constructor MyNamespace.MyClass.Logger(System.Type myConstructorParameter).
Exception is: InvalidCastException - Unable to cast object of type 'MyActualInstanceOfTypeProvidedToConstructor' to type 'System.Type'.
-----------------------------------------------
At the time of the exception, the container was:

Resolving MyNamespace.MyClass,(none) (mapped from MyNamespace.IMyInterface, (none))\r\n  Resolving parameter \"myConstructorParameter\" of constructor MyClass(System.Type myConstructorParameter)
Solving this issue is not as complicated as the error message may seem... for unity. Microsoft did left some flexibility for us, it simply involves wrapping the type argument as an injection parameter:
new ParameterOverride("typeParameterArgument",new InjectionParameter(typeof(Type),typeof(MyNamespace.MyClassUsedAsInjectedTypeArgument)))
Why? if you dive into the reflection tool of your choice you will eventually come across "InjectionParameterValue.ToParameter" this little gem will show you that unity is checking to see of the value is an InjectionParameterValue if it is no and the value is a type return a new ResolveParameter using the argument as a type.
References:

Wednesday, February 15, 2012

MVC3 controller action model argument is null

After re-naming some controller action arguments I recently discovered a method that was previously working, unexpectedly returning null for the controller action argument. The action used the default model binder pulling data from both the query string and route values. Consider the following code:

public class Search
{
  public string Name {get;set;}
  public string Query {get;set;}
}
public ActionResult Results(Search query)
{
....
}
....
///results/{Name}
....
///results/monkeys?Query=12-of-them-jumping


The default model binder rather than binding to the object is trying to take your "Query" and plug it into the action method as an argument. Since string is not "Search" it results in a null value, the short lesson to take from this puzzle is to avoid naming properties on your object the same name as arguments you are passing into the controller action.

Thursday, December 15, 2011

TSQL SELECT Convert or Cast DateTime but WHERE fails

Can a select return when a where fails?

This zen like question came up this afternoon while digging through some rather raw varchar table data. The answer is yes, and part of answer is coming up with the right question. While googling around I ended up settling on "CONVERT fails in where clause but not in select".

Consider the following problem:
SELECT * FROM dbo.MyTable
WHERE ISDATE(value)=1 AND AND  CAST(Value AS datetime) > GETUTCDATE()

--OR

SELECT * FROM dbo.MyTable
WHERE ISDATE(value)=1 AND CONVERT(datetime,Value) > GETUTCDATE()

Value
-----------------------
2012-01-02 00:00:00.000

--BUT

SELECT CONVERT(datetime,Value) FROM dbo.MyTable
WHERE ISDATE(value)=1

--OR

SELECT CAST(Value AS datetime) FROM dbo.MyTable
WHERE ISDATE(value)=1

Msg 241, Level 16, State 1, Line 1
--HUH?
Conversion failed when converting date and/or time from character string.

To paraphrase the above, SQL Server may evaluate rows outside of the expected WHERE clause based on how the optimizer decides to limit the result set. This left me with three solutions:

  1. Create an index to persuade the optimizer to avoid the alternate plan that evaluates non date columns (query condition that would allow you to do this not shown in examples. I am sure you can find one if you join a few things and look at the plan.)

  2. Reload cast or converted data into a #temporary table

  3. My solution below compliments of least resistance add some case logic around the value column
SELECT Value FROM dbo.MyTable
WHERE CASE ISDATE(value)=1 THEN CONVERT(datetime,Value)
ELSE NULL END > GETUTCDATE()
--OIC :)


When you think about how SQL Server has to discover the table data it makes sense. If you haven't run into the condition before it may cause a little head scratching. Hopefully with this post and the corresponding stackoverflow post you can save a few extra hairs on your head.

Tuesday, September 20, 2011

Azure Security Certificate Names Are Case Sensitive

If you receive the following error and are not using a proxy, and do not have Fiddler open, you might have some mixed case somewhere in your certificate name configuration settings:

1:55:36 PM - Warning: There are package validation warnings.
1:55:36 PM - Preparing...
1:55:36 PM - Connecting...
1:55:38 PM - Uploading...
1:56:25 PM - Creating...
1:56:42 PM - HTTP Status Code: 500/nError Message: The server encountered an internal error. Please retry the request./nOperation Id: {GUID}
1:56:43 PM - Deleting Quality Assurance Debug Only - Website
1:56:44 PM - There was no endpoint listening at https://management.core.windows.net/{GUID}/services/hostedservices/website/deploymentslots/Staging that could accept the message. This is often caused by an incorrect address or SOAP action. See InnerException, if present, for more details.
1:56:44 PM - Deployment failed

Friday, September 9, 2011

Windows Azure Multi-Site Single Role Using Host Headers With Config Transforms

I was excited to find out that Azure supported multiple sites with a single worker role with a few simple configuration changes thanks to Wade Wegner's Example. I was a little disappointed that the process of building the package did not include the XDT transforms on the config. Neither is the website packaged for deployment which strips out all non essential files references in the web application before deploying. After a number of google searches and some trial and error I came up with the following solution:


In my example I created a single website and associated it to my azure project as the only worker role.

In the worker role pre-build event I have placed the following for each website that needed to be packaged and transformed:

Cloud Project Pre Build Event

rmdir ..\Deploy.Cloud\Website.Mvc /S /Q
"%systemroot%\Microsoft.NET\Framework64\v4.0.30319\MSBuild.exe" "$(ProjectDir)..\Website.Mvc\Website.Mvc.csproj" "/p:Platform=AnyCPU;PackageAsSingleFile=False;Configuration=$(ConfigurationName);DesktopBuildPackageLocation=..\Package\Website.Mvc;PackageAsSingleFile=False;IntermediateOutputPath=..\Deploy.Cloud\Website.Mvc\\" /t:Package

*You must remove the intermediate location before it creates the package otherwise debug/release configurations will not differ

*Note the extra slash at the end yes that is intentional if you do not add it you will get some interesting error messages about properties with no value

ServiceDefinition.csdef

<Site name="Website.Mvc" physicalDirectory="Website.Mvc\Package\PackageTmp">


What's going on here
Every time the cloud project builds it will copy and package the website in the cloud project's project root folder as the website name. Next step is to update the ServiceDefinition.csdef use the intermediate path location for the physicalDirectory. Why? because the package directory contains all of the assets to be deployed as a web deployment project which is not needed when deploying using a web role.


References

Wednesday, August 17, 2011

Windows Azure Accelerator for Web Roles Missing Trace Logging By Default

After upgrading our applications to Windows Azure Accelerator for Web Roles I found that the trace messages disappeared. Windows Azure Accelerator for Web Roles default project does not enable trace logging by default. To fix this simply add the following lines to the WebRole.cs of the Windows Azure Accelerator for Web Role project.

private static void ConfigureDiagnosticsMonitor()
{
//... Omitted from example
// Trace Logs
diagnosticMonitorConfiguration.Logs.ScheduledTransferLogLevelFilter = LogLevel.Undefined;
diagnosticMonitorConfiguration.Logs.ScheduledTransferPeriod = TimeSpan.FromMinutes(1);
//... Omitted from example
}

Tuesday, February 8, 2011

Using XDT with Worker Role App.configs

Recently I wrote a worker role in windows azure and was hoping the app.config would transform much like the web.config in the web roles. Sadly this is not the case. The configuration transforms are very useful when making a distinction between production, staging and development environments. After a little research, I did discover how to roll my own hopefully Microsoft will extend this feature to the rest of the azure project types.

Like the web roles this transform is only executed when a deploy is executed, here is how it was done:

  1. Un-load the project containing your worker role and app.config
  2. Edit the project file at the bottom add the following lines:

    <usingtask taskname="TransformXml" assemblyfile="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.Tasks.dll">
    <target name="AfterCompile" condition="exists('app.$(Configuration).config')">
    <transformxml source="app.config" destination="$(IntermediateOutputPath)$(TargetFileName).config" transform="app.$(Configuration).config">
    </transformxml></target>
    </usingtask>


  3. Add the following Item Group:

    <ItemGroup>
    <Content Include="App.config" />
    <Content Include="App.Debug.Config">
    <DependentUpon>App.Config</DependentUpon>
    <SubType>Designer</SubType>
    </Content>
    <Content Include="App.Release.Config">
    <DependentUpon>App.Config</DependentUpon>
    </Content>
    </ItemGroup>
  4. Now add the new configuration files to the project App.Debug.config, App.Release.config
  5. Reload the worker role project project
  6. Unload the cloud service project that references the worker role
  7. Open the file for edit and add the following line:

    <Target Name="CopyWorkerRoleConfigurations" BeforeTargets="AfterPackageComputeService">
    <Copy SourceFiles="..\{PROJECT PATH}\obj\$(Configuration)\{ASSEMBLY NAME}.dll.config" DestinationFolder="$(IntermediateOutputPath)\{PROJECT NAME}" OverwriteReadOnlyFiles="true"/>
    </Target>

  8. Reload the project file

You will need to use the name of your project and the assembly name in the locations above. The paths are relative to the azure service project file. If you get lost you can add an element to the target and set the text to your path.