Sunday, December 11, 2011

Tuesday, October 11, 2011

WCF - Store and Forward

When designing WCF services, specifically, OneWay operation contracts, developers usually expect the service to be stable. One doesn’t consider network instability between the service and its clients.

That’s why, many messaging engine, such as BizTalk and Tibco EMS has a built-in feature called Store and Forward.  That is, the client doesn’t consume the service directly but rather publish the messages into a store, and then the messaging engine peeks on the message store and route it to pre-designated subscribers. This architecture pattern is called Pub/Sub. You can look it up here.

In WCF world, developers have the facility to build this store and forward capability using MSMQ binding (netMsmqBinding). However, MSMQ has a lot of networking issues, especially if it’s used as a network resource in a multi-forest or multi-domain environment.

I have worked on a small-scale solution to accomplish this task using a database message store. It’s built on the following components:
 

  1.  Router: the router is called by the client. Currently it’s a stateless router based on WCF 4.0 routing service (http://msdn.microsoft.com/en-us/library/ee354381.aspx - Routing Service).
  2. Persistence Service: a WCF service with a single Operation Contract (Publish). It’s used to publish WCF messages into the message store.
  3. Message Store: a database to store WCF messages.
  4. Message Processor: Peeks the message store for new messages based on subscriptions and route them to subscribers.
  5. Subscription Manager: a WCF service used to subscribe or unsubscribe. It has two Operation Contracts. Subscribe and Unsubscribe.

Known Issues:
Ø  It works only with basicHttpBinding.
Ø  Subscription manager is not testedJ
Ø  It uses the SOAP action to route messages. That means that you’ll have to subscribe for each SOAP action. I’m planning to use Regex to match subscriptions instead.
Ø  It’s not tested with large messages (> 4mb). I believe it will need some work to adjust the readerQuotas on the channel binding.
The solution code and database script can be found here.

Monday, September 5, 2011

Quick comparison: WCF Vs Web Services (SOAP)


Web Services (SOAP)
WCF
Service Attribute
WebService
ServiceContract
Operation Attr.
WebMethod
OperationContract
Message Attr.
Serializable
DataContract
MessageContract
DataMember
MessageHeader
MessageBody
Binding
1 binding – SOAP (XML/HTTP)
Multiple (wsHttpBinding, wsBasicBinding, …)
You can implement your own
Transport
HTTP
Multiple
You can implement your own
End Points
1 end point (ASMX)
Multiple
Serialization
XML Serializer
DataContractSerializer (Default)
You can override the behavior or implement your own serializer
Address format
Http://*****
depends on the binding used
Late binding
Not supported
Supported thru configuration
Hosting
IIS
IIS, Console, Windows Service, …
Authentication
Web application authentication
Username, X509, SAML, Cardspace, custom
Impersonation
Impersonated by Application Pool User
Can be impersonated by current caller.
[OperationBehavior(Impersonation = ImpersonationOption.Required)]
Channel Model
Not supported
Full channel model stack – developers can implement any layer of this stack and plug it in thru configuration

Saturday, July 23, 2011

Generate DataContract from an XML Schema

In the contract-first development approach, one can generate data contracts using an XML Schema.


Use WCF ServiceModel Metadata Utility Tool (Svcutil.exe) to generate DataContract type source code based on any XML Schema. Following is the sample command on how to use the Svcutil.exe tool:



svcutil.exe /target:code /dataContractOnly /serializer:DataContractSerializer /importXmlTypes MySchema.xsd


source: http://msdn.microsoft.com/en-us/magazine/cc163800.aspx

Thursday, July 21, 2011

Security Exception - Medium trust ASP.NET application consumes an external web service

you will encounter the below error if your asp.net application uses a medium trust level (<trust level="medium">) and it tries to consume an external web service.


Description: The application attempted to perform an operation not allowed by the security policy.  To grant this application the required permission please contact your system administrator or change the application's trust level in the configuration file. 

Exception Details: System.Security.SecurityException: Request for the permission of type 'System.Net.WebPermission, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' failed.



[SecurityException: Request for the permission of type 'System.Net.WebPermission, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' failed.]
   System.Security.CodeAccessSecurityEngine.Check(Object demand, StackCrawlMark& stackMark, Boolean isPermSet) +0
   System.Security.CodeAccessPermission.Demand() +58
   System.Net.HttpWebRequest..ctor(Uri uri, ServicePoint servicePoint) +147
   System.Net.HttpRequestCreator.Create(Uri Uri) +26
   System.Net.WebRequest.Create(Uri requestUri, Boolean useUriBase) +216
   System.Net.WebRequest.Create(Uri requestUri) +31
   System.Web.Services.Protocols.WebClientProtocol.GetWebRequest(Uri uri) +32
   System.Web.Services.Protocols.HttpWebClientProtocol.GetWebRequest(Uri uri) +15
   System.Web.Services.Protocols.SoapHttpClientProtocol.GetWebRequest(Uri uri) +4
   System.Web.Services.Protocols.SoapHttpClientProtocol.Invoke(String methodName, Object[] parameters) +52
   myService.MyWebMethod() in App_WebReferences.tbvx_k59.3.cs:153
   Positions.Page_Load(Object sender, EventArgs e)
   System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr fp, Object o, Object t, EventArgs e) +14
   System.Web.Util.CalliEventHandlerDelegateProxy.Callback(Object sender, EventArgs e) +35
   System.Web.UI.Control.OnLoad(EventArgs e) +99
   System.Web.UI.Control.LoadRecursive() +50
   System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +6785
   System.Web.UI.Page.ProcessRequest(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +242
   System.Web.UI.Page.ProcessRequest() +80
   System.Web.UI.Page.ProcessRequestWithNoAssert(HttpContext context) +21
   System.Web.UI.Page.ProcessRequest(HttpContext context) +49
   ASP.careers_positions_aspx.ProcessRequest(HttpContext context) in App_Web_x4ylsrid.0.cs:0
   System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +181
   System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +75
Why this happens?

By default, medium-trust policy grants ASP.NET Web applications a restricted WebPermission

Resolution:


To be able to call Web services from your Web application, you must configure the originUrl attribute on your application's <trust> element.


To call a single Web service from a medium trust Web application
  1. Configure the application to run at medium trust.
  2. Set the originUrl to point to the Web service you want to be able to call, as follows:
    <trust level="Medium" originUrl="http://servername/.*"/>
    
The originUrl value is used in the constructor for a System.Text.RegEx regular expression class so that in can perform a match on the URLs that are accessible by the Web service. This RegEx class is used in conjunction with a WebPermission class. The ".*" matches any URL beginning with "http://servername/".
The originUrl attribute is used when ASP.NET policy is evaluated. It gives a value for the $OriginHost$ substitution parameter. Here is the WebPermissiondefinition from Web_mediumtrust.config:
<IPermission
   class="WebPermission"
   version="1">
   <ConnectAccess>
     <URI uri="$OriginHost$"/>
   </ConnectAccess>
</IPermission>
If you do not specify the Web servers accessed by your application, any Web service request will fail with a SecurityException. To call a Web service on the local Web server, use the following configuration:
<trust level="Medium" originUrl="http://localhost/.*" />
If your application needs to access multiple Web services on different servers, you need to customize ASP.NET policy because you can only specify one originUrlon the <trust> element in Web.config or Machine.config.
To call multiple Web services from a medium-trust application
  1. Copy the Web_mediumtrust.config file, which is in the following directory, to a file called Web_mediumtrust_WebService.config, which is located in the same directory.
    %windir%\Microsoft.NET\Framework\{version}\CONFIG
    
  2. Locate WebPermission and add a <URI> element for each server you will be accessing, as follows:
    <IPermission class="WebPermission" version="1">
      <ConnectAccess>
        <URI uri="$OriginHost$"/>
        <URI uri="http://server1/.*"/>
        <URI uri="http://server2/.*"/>
        <URI uri="http://server3/.*"/>
      </ConnectAccess>
    </IPermission>
    
    If you call the Web service using its NetBIOS) name, DNS name, and/or IP address, you must have a separate <URI> element for each URI as shown in the following example.
    <IPermission class="WebPermission" version="1">
      <ConnectAccess>
        <URI uri="$OriginHost$"/>
        <URI uri="http://servername.yourDomain.com/.*"/>
        <URI uri="http:// servername/.*"/>
        <URI uri="http://127.0.0.1/.*"/>
      </ConnectAccess>
    </IPermission>
    
  3. Save the file.
  4. Update your application's Web.config file to point to the newly created policy file. This requires that you create a new trust level and map it to the new policy file. Next, configure the <trust> element of your application to use the new level.
    The following fragment shows the necessary additions to Web.config:
    <system.web>
      <securityPolicy>
        <trustLevel name="MediumPlusWebPermission" 
                    policyFile="web_mediumtrust_WebService.config"/>
      </securityPolicy>
      <trust level=" MediumPlusWebPermission" originUrl=""/>
    </system.web>
    Source: http://msdn.microsoft.com/en-us/library/Aa302425
    
    
    Happy coding!