Friday, June 20, 2008

CAB/SCSF: View Parameters

CAB/SCSF use the wellknown Model-View-Presenter design pattern for its views. There is, however, a design flaw in its implementation: you cannot pass parameters to the view constructor. As documenten in the SCSF knowledge base, the proven practice is to pass the parameters using the WorkItem State collection.

This proven practice can be improved using generics to become type-safe, while still adhering to the MVP design rules. Add the following new method to the WorkItemController base class in the Infrastructure.Interface project:

public virtual TView ShowViewInWorkspace<TView, TParams>(string viewId, string workspaceName, TParams viewParams)
where TParams : class
{
string stateKey = StateItemNames.PresenterConstructorParams + typeof(TView).FullName + ":" + typeof(TParams).FullName;
_workItem.State[stateKey] = viewParams;

TView view = ShowViewInWorkspace<TView>(viewId, workspaceName);
return view;
}

Then add the following new method to the Presenter base class in the Infrastructure.Interface project:

protected TParams ViewParameters<TParams>() where TParams : class
{
//NOTE: must use typeof(view instance) to get correct run-time type of generic view type
string stateKey = StateItemNames.PresenterConstructorParams + _view.GetType().FullName + ":" + typeof(TParams).FullName;
return (TParams)_workItem.State[stateKey];
}

Now you can simply pass the parameters from the module controller to the view using ShowViewInWorkspace and then get the parameters in the presenter's OnViewReady event:

_viewParameters = ViewParameters<ViewParameters>();
if (_viewParameters == null)
{
throw new ArgumentException("Required view parameter error", "ViewParameters", null);
}

This little design improvement hides the gory details of using the untyped object State collection, e.g. generating shared keys and type casting.

Wednesday, June 18, 2008

WCF: Using Shared Types

In WCF you can use shared types from existing assemblies when generating a service proxy. Use the advanced options in VS2008, otherwise use SVCUTIL.EXE with the /reference /r option. Note that you can only use /reference when your WSDL operations, types and messages adheres to the DataContractSerializer rules that I described this spring.

I'm currently trying to research why we are not able to use shared types for our wsdl:fault message parts.

<wsdl:message name="GetCustomerRequest">
<wsdl:part element="tns:GetCustomerRequest" name="parameters" />
</wsdl:message>
<wsdl:message name="GetCustomerResponse">
<wsdl:part element="tns:GetCustomerResponse" name="parameters" />
</wsdl:message>
<wsdl:message name="FaultDetailList">
<wsdl:part element="fault:FaultDetailList" name="detail" />
</wsdl:message>

<wsdl:portType name="CustomerService">
<wsdl:operation name="GetCustomer">
<wsdl:input message="tns:GetCustomerRequest" name="GetCustomerRequest" />
<wsdl:output message="tns:GetCustomerResponse" name="GetCustomerResponse" />
<wsdl:fault message="tns:FaultDetailList" name="FaultDetailList" />
</wsdl:operation>
</wsdl:portType>


<wsdl:binding name="CustomerServiceSoap11" type="tns:CustomerService">
<soap:binding style="document" transport="
http://schemas.xmlsoap.org/soap/http" />
<wsdl:operation name="GetCustomer">
<soap:operation soapAction="" />
<wsdl:input name="GetCustomerRequest">
<soap:body use="literal" />
</wsdl:input>
<wsdl:output name="GetCustomerResponse">
<soap:body use="literal" />
</wsdl:output>
<wsdl:fault name="FaultDetailList">
<soap:fault name="FaultDetailList" use="literal" />
</wsdl:fault>
</wsdl:operation>
</wsdl:binding>

Even if the fault details contains only xs:string elements, we get this error when generating the proxy:

Cannot import wsdl:portTypeDetail: An exception was thrown while running a WSDL import extension: System.ServiceModel.Description.DataContractSerializerMessageContractImporterError: Referenced type 'SharedDataContracts.FaultDetailType, MyService, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' with data contract name 'FaultDetailType' in namespace 'urn:kjellsj.blogspot.com/FaultDetail/1.0' cannot be used since it does not match imported DataContract. Need to exclude this type from referenced types.

I thought that writing a unit-test to import the WSDL using the underlying SVCUTIL importer directly should help me deduce the cause of the error. You will find all the code that you need to import WSDL using DataContractSerializerMessageContractImporter here at the "nV Framework for Enterprise Integration" project as CodePlex.

Add these lines to enforce the use of /namespace, /reference and /ct from code (note that these switches can be used multiple times):

xsdDataContractImporter.Options.Namespaces. Add(new KeyValuePair<string, string>("*", "MyService"));
xsdDataContractImporter.Options.ReferencedCollectionTypes. Add(typeof(List<>));
xsdDataContractImporter.Options.ReferencedTypes. Add(typeof(SharedDataContracts.FaultDetailList));
xsdDataContractImporter.Options.ReferencedTypes. Add(typeof(SharedDataContracts.FaultDetailType));

Sure enough, I get the exact same exception in my unit-test. Inspecting the imported contract shows that the operation has a fault with a "null" DetailType XML Schema type (watch: contracts[0].Operations[0].Faults[0].DetailType). I suspect that it is the "null" DetailType in the FaultDescription of the imported ServiceDescription for the WSDL that causes the error for the referenced shared types.

As it turns out this is a bug that has been fixed in .NET 3.5 SP1. The workaround for earlier versions of SVCUTIL is to add nillable="true" to all elements that are reference types (strings and complexTypes) in your wsdl:types XSD schemas. Or just drop the /reference switch and cut'n'paste the generated code to use your shared types.

Thursday, May 22, 2008

SOA Canonical Cross-Domain Data Semantics

I have over the last year promoted the need for having a business process information model (BPIM) for semantic mediation and business process integration to enable SOA, not to forget enabling consumers such as mashups to do composition and consumption of the provided services, to deliver value to our users.

There has been some discussions about the need for an enterprise to have federated canonical domain models, but I think more and more people tends to believe that BPIM is an important SOA and BPM enabler. This blog post by Joe McKendrick quotes Hub Vandervoort, CTO of Progress Software, on some common SOA challenges:

He recommended three approaches to the problem, including "getting your transports aligned between business entities so that you can use eventing-oriented mechanisms to communicate across domains"; establishing SLA and security policies that ensure visibility; and establishing a common enterprise data model.

"You have to get your semantics aligned among the members," he said. "And that doesn't have to be a common vocabulary in its entirety, but certainly what we regard as the data in flight, those things that fly between domains and different working groups have to be highly normative."

The important part of Vandervoort's message is that you should not try to make a complete Enterprise Data Model, but rather focus on a common information model (CIM) for the "data in flight", i.e. the events, messages and documents of your business processes, when creating your information model.

Thursday, May 15, 2008

Configure MSE UDDI Integration

The Managed Services Engine repository can be synchronized with UDDI. All service endpoints hosted on an MSE runtime server can be exported to make your virtualized services discoverable from e.g. VisualStudio. View this web-cast (slide deck) by Raul Camacho to learn about SOA lifecycle management and MSE service virtualization.

Enable and configure the UDDI sync using the <serviceCatalogUddi> element in the config file of the MSE catalog service executable on the MSE server (Microsoft.MSE.Catalog.ServiceHost.exe.config).

NOTE: In UDDI Services, data published for a service, provider, or tModel can be modified only by the current owner. Make sure that the identity used to publish MSE data to UDDI is the owner of the configured UDDI provider (BusinessKey).

The UDDI sync configuration must adhere to these rules:

  • Make sure that you use the "uddipublic" URLs for "UDDI" authN
  • Make sure that you use the "uddi" URLs for "WINDOWS" authN
  • The identity used to run the MSE catalog service must have access to the UDDI web-services
  • The identity specified for the sync must have publish rights in UDDI and own the BusinessKey
The UDDI Services Console MMC snap-in must be used to configure domain groups for the different UDDI roles, including "publisher" rights.

Using "WINDOWS" authN is strongly recommended. You can specify "UDDI" as the <UddiAuthenticationScheme> and put a username + password of an identity that has access to UDDI in the config file to test the UDDI sync. Do not do this for production systems.

<!-- DO NOT CHANGE THE ORDER OF THE ELEMENTS -->
<serviceCatalogUddi>

<UddiIntegrationMode>true</UddiIntegrationMode>
<UddiPublishUrl>http://***/uddipublic/publish.asmx</UddiPublishUrl>
<UddiInquireUrl>http://***/uddipublic/inquire.asmx</UddiInquireUrl> <BusinessKey> UDDI PROVIDER GUID HERE </BusinessKey>
<UddiAuthenticationScheme>UDDI</UddiAuthenticationScheme>
<UddiUserName>***\***</UddiUserName>
<UddiPassword>*******</UddiPassword>
</serviceCatalogUddi>


Check the UDDI config if you have problems when publishing services and also check the Application Event Log. Use the MMC UDDI Services Console to adjust the logging level to diagnose errors. Note that you must set the level to info / verbose to see SQL exceptions, e.g. when you get an error like this:

Failed to Publish EndPoint service to UDDI due to error [Exception Information Type[FaultException] Message[A UDDI specific error occurred while publishing Endpoint data to UDDI] ].

Using "WINDOWS" against "uddipublic" will give you this error in the event log: UDDI_ERROR_AUTHTOKENREQUIRED_NOTOKENPUBLISHATTEMPT

Note that the UDDI web-portal requires ASP.NET 1.x. Check that the IIS web-sites use ASP.NET 1.x if the UDDI web-pages have errors (e.g. the treeview fails).