Archive

Posts Tagged ‘C#’

Dynamically adding RaisePropertyChanged to MVVM Light ViewModels using Microsoft Unity

July 28, 2011 3 comments

Introduction

In the past, I already wrote two articles about dynamically adding RaisePropertyChanged support to view models. Today, I will explain how this can be accomplished with the IoC container: Microsoft Unity. Unity has out of the box support for AOP. Using Unity is much easier than my two previous do-it-yourselves ways. For real applications, I recommend using Unity or similar frameworks!

Like in my previous articles, I want to write view models using the following code pattern:

[RaisePropertyChanged]
public virtual string SomeProperty { get; set; }

Instead of the standard pattern:

private string someProperty;

public string SomeProperty
{
    get
    {
        return someProperty;
    }
    set
    {
        someProperty = value;
        RaisePropertyChanged("SomeProperty");
    }
}

Implementation

In order to get started, the first thing we have to do is install both Unity and MVVM Light. To do this, I recommend using Nuget. In the official Nuget repository, Unity is split into two packages. For the AOP support, both packages need to be added to the Visual Studio project.

nuget_Unity

Now that we have all the required libraries, we can start coding. First, lets define our RaisePropertyChangedAttribute class.

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class RaisePropertyChangedAttribute : HandlerAttribute
{
    public override ICallHandler CreateHandler(IUnityContainer container)
    {
        return new RaisePropertyChangedCallHandler();
    }
}

Because we want Unity to intercept calls, we must extend our attribute from HandlerAttribute. A custom HandlerAttribute must create and return a custom ICallHandler instance. We will return an instance of our custom RaisePropertyChangedCallHandler that we will create next.

Before writing our ICallHander, we must first look at the MSIL code generated by the C# compiler in order to understand .Net properties better. When a property is defined, 2 hidden methods are automatically created by the compiler; a get method and a set method. These methods have by default the name get_<property name> and set_<property name>.

Ildasm_property

With this knowledge in mind, the custom ICallHandler implementation is straightforward. We ask Unity to call the original set method and after its invocation we extract the name of property out of the name of the set method and we invoke the RaisePropertyChanged method of MVVM Light using reflection.

class RaisePropertyChangedCallHandler : ICallHandler
{
    public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
    {
        IMethodReturn methodReturn = getNext()(input, getNext);

        string propertyName = input.MethodBase.Name.Substring(4);

        MethodInfo raisePropertyChangedMethod = input.Target.GetType().GetMethod("RaisePropertyChanged",
            BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[] {typeof(string)}, null);
        raisePropertyChangedMethod.Invoke(input.Target, new object[] { propertyName });

        return methodReturn;
    }

    public int Order { get; set; }
}

Configuring Unity

All that now remains is configuring Unity for our view model and activating virtual method AOP support for it. In code, we can define this using the following code sample:

IUnityContainer container = new UnityContainer();
container.AddNewExtension<Interception>();
container.RegisterType<SampleViewModel>().
    Configure<Interception>().
    SetInterceptorFor<SampleViewModel>(new VirtualMethodInterceptor());

If we now use Unity for creating instances of our sample view model class, all the properties annotated with “RaisePropertyChanged” will atomically be “property change”-aware.

SampleViewModel vm = container.Resolve<SampleViewModel>();

Please note: This will not work in Silverlight, because of limitations in its runtime. (Silverlight does not allow the invocation of private methods using reflection for security reasons)

Advertisements
Categories: C#, IoC, MVVM, WPF Tags: , , , ,

Using the WCF Service Moniker to communicate between legacy COM applications and new .Net applications

October 5, 2010 29 comments

Introduction

Software engineering is maybe the only engineering discipline were building an entirely new wing to a building is considered maintenance. Applications are extended and modified for years. Applications that once used the most modern technologies of the organization have become legacy themselves, yet in a lot of the cases we want them to be able to communicate with their new siblings.

If your organization used Microsoft Visual Basic in the past, you will probably be migrated to .Net by now. Visual Basic is build around Microsoft’s COM technology, a technology that a lot of developers refer to as “the DLL hell”. With .Net Microsoft has made a clean start. At the same time they made interoperability between .Net and COM possible, but that means that your COM interop assemblies will suffer of the same problems as your old components did in the past.

Enterprise applications build today are using n-tier architectures, where the communication between the backend and the fronted in Microsoft environments is mostly done using (WCF) web service technology. Therefore I will present you another choice for interoperability between COM based applications and the new .Net applications: the COM Service Moniker.

The COM Service Moniker

The Microsoft COM Service Moniker is automatically installed when you install the .Net framework. It can be used in 3 ways:

  1. Using a typed contract
  2. Using a MEX endpoint
  3. Using the WSDL of the web service

In this article I will show you how to consume a simple WCF service using a typed contract and using the MEX endpoint. The COM client used for this demo will be developed in Excel VBA, but you could develop it in every programming language that supports COM components.

The demo WCF service

We will create simple WCF service that accepts a string as input and returns a strings as output. First we create a new “WCF Service Application”:

Inside the project: we create the following service contract:

[ServiceContract]
public interface IHelloName
{
 	[OperationContract]
	string Hello(string name);
}

We implement the service as follows:

public class HelloName : IHelloName
{
	public string Hello(string name)
	{
		return "Hello " + name;
	}
}

Although it is not mandatory anymore with WCF 4.0 to configure the end points, we need to do this for the tutorial because we will need a mex endpoint for the second example. This is not exposed by default in WCF. The configuration for our service is the following:

<system.serviceModel>
	<services>
		<service behaviorConfiguration="serviceBehavior"
		         name="HelloNameService.HelloName">
			<endpoint binding="basicHttpBinding"
				      bindingName="BasicHttpBinding_IHelloName"
			          contract="HelloNameService.IHelloName" />
			<endpoint address="mex"
					  binding="mexHttpBinding"
					  contract="IMetadataExchange" />
		</service>
	</services>
	<behaviors>
		<serviceBehaviors>
			<behavior name="serviceBehavior">
			    <serviceMetadata httpGetEnabled="true" />
				<serviceDebug includeExceptionDetailInFaults="false" />
			</behavior>
	    </serviceBehaviors>
	</behaviors>
	<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>

This needs to be added into the web.config of the WCF service project.

We are now done with our WCF service, so you can press F5 to start the WCF service.

Consuming a WCF service using a typed contract

Creating the typed contract

First we are going to use svcutil.exe to create the source for a WCF client application for our service. To do this, start the Visual Studio Command Line and use the following command:

Svcutil.exe http://localhost:49170/HelloName.svc /config:EXCEL.EXE.config

You should notice that the tool creates 2 files: “HelleName.cs” and “EXCEL.EXE.config”. The “.cs” file will in a minute be added to a Visual Studio class library project while the “.config” file must be placed in the same location as EXCEL.EXE.

Remark: Please make that the port number is the correct one for the WCF service running on your system.

Remark 2: If your COM application has another name then EXCEL.EXE, you should name the config file “<appname>.exe.config”.

Next we create a cryptographic key pair with: “sn.exe –k helloKey.snk”.  You only need to perform this step once; if you recompile our recreate your typed contract you should reuse the same key pair.

Now we are going to create the class library that will contain our typed contract: create a new Class Library project and the source file generated in step 1 to I and modify the AssemblyInfo.cs to set ComVisible to true.

[assembly: ComVisible(true)]

To compile the class library we must also add a reference to “System.ServiceModel”.

 

 

<!–[if gte mso 9]> <![endif]–><!–[if gte mso 9]> Normal 0 21 false false false NL-BE X-NONE X-NONE <![endif]–><!–[if gte mso 9]> <![endif]–> <!–[endif]–>First we are going to use svcutil.exe to create the source for a WCF client application for

And the cryptographic key created must be added in the signing tab:

Now we can just compile our assembly with Visual Studio and afterwards we register the types in the compiled assembly with “Regasm.exe”. This allows the types to be used in the COM environment:

Regasm.exe <projectpath>\bin\Release\HelloNameContract.dll /tlb

After the tlb is created we are going to open it to view its UUID; therefore enter “oleview” in the Visual Studio command prompt to launch the Microsoft OLE/COM Object Viewer and choose File > View TypeLib and choose the tlb file generated in the previous step. Write down the UUID for IHelloName, because we will need it in a minute.

Finally, we register our assembly inside the GAC:

Gacutil.exe /i <projectpath>\bin\Release\HelloNameContract.dll

Creating the COM client

Now it is time to fire up Microsoft Excel and to open the VBA editor. First to add a reference to typelib we just created for the typed contract.

Finally add the following code to create the service moniker:

Sub ServicemonkercallTyped()
    Dim service As IHelloName
    Dim monString As String

    monString = "service4:address=http://localhost:49170/HelloName.svc," & _
                "binding=basicHttpBinding, bindingConfiguration=BasicHttpBinding_IHelloName," & _
                "contract={3EA9FDEB-1AC5-324D-A7CA-F74422CF4415}"

    Set service = GetObject(monString)

    MsgBox (service.Hello("Excel Typed"))
End Sub

We are now ready to launch the VBA code. You should see the following message:

Remark: In my example I have used Visual Studio 2010 to compile and sign the assembly, but of course you could automate all the steps completely by using MSBuild.

Consuming a WCF service using a MEX endpoint

If you don’t mind static typing or if you don’t want to have a dependency on the type library; using a MEX endpoint can be a good alternative. If you have not done this already, first configure the WCF service to expose the MEX endpoint.

Finally we must add the following code inside our VBA client:

Sub ServicemonkercallMex()
    Dim service As Object
    Dim monString As String

    monString = "service4:mexaddress=http://localhost:49170/HelloName.svc/mex" & _
                ", address=http://localhost:49170/HelloName.svc" & _
                ", contract=IHelloName, contractNamespace=http://tempuri.org/" & _
                ", binding=BasicHttpBinding_IHelloName_IHelloName, bindingNamespace=http://tempuri.org/"

    Set service = GetObject(monString)

    MsgBox (service.Hello("Excel Mex Endpoint"))
End Sub

If you should have customized the contract namespace or the binding namespace, then you should modify them in the connection string. Otherwise “http://tempuri.org/” is always the default value in WCF for both namespaces.

If you launch the VBA code, you should see the following message:

Debugging the COM Service Moniker

If you have made errors while implementing the samples yourself; you will have noticed that exceptions returned by the GetObject call are rather cryptic. Is hard to discover the cause error with a rather general message like “Automation error, Invalid syntax”.

Luckily I have found 2 ways to debug the COM Service Moniker. The moniker is implemented in C# which allows you to intercept its exceptions using the Visual Studio debugger. To do this: we must first configure our Visual Studio debugger to also break on external code, goto: “Tools > Options > Debugging > Enable Just My Code (Managed only)” and uncheck it.

Next we must attach our debugger to the Excel process: “Debug > Attach to process”.

Now, we are ready to relaunch our VBA code, when an exception occurs inside the Service Moniker the Visual Studio will break and show you the managed message.

Although the Visual Studio debugger is a good choice for use in a developer environment; it is impractical in a test or server environment. By using Relfector; I discovered that the Service Monikes uses the System.Diagnostics framework. We can thus configure the moniker to trace its activity. We will configure this with a tool that is part of the Windows SDK: “Microsoft Service Configuration Editor”. The default location for this tool is “C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\SvcConfigEditor.exe”.

Open the EXCEL.EXE.config created earlier with the Service Configuration Editor and go to the diagnostics information. On that screen you need to enable the tracing and the auto flush.

Besides the Service Configuration Editor, the Windows SDK also contains a tool to view the WCF trace files. You can find it at “C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\SvcTraceViewer.exe”. When we now restart Excel and relaunch our VBA code, we can see the more readable description of the exception in the trace viewer.

Remark: In a production environment you should not enable auto flush because it will hurt performance.

Conclusion

In this article I have shown a lesser know method for communication between COM based applications and their .Net cousins. Hopefully the examples where clear for all to understand and I hope that I made my point clear that the Service Moniker is a very powerful feature. Altough I have used Visual Studio 2010, you could also use Visual Studio 2008 and .Net 3.5 for the implementation of the WCF service. If you have further questions, don’t hesitate to contact me.

Categories: C#, WCF Tags: , , ,