From 4fc027146c5a10b72a40c7ad20c265c193b180ad Mon Sep 17 00:00:00 2001 From: markpollack Date: Wed, 13 Aug 2008 05:07:16 +0000 Subject: [PATCH] Added WCF documentation misc updates. --- doc/reference/src/index.xml | 5 + doc/reference/src/messaging.xml | 21 ++- doc/reference/src/wcf.xml | 286 ++++++++++++++++++++++++++++++++ 3 files changed, 303 insertions(+), 9 deletions(-) create mode 100644 doc/reference/src/wcf.xml diff --git a/doc/reference/src/index.xml b/doc/reference/src/index.xml index 00c86dcd..40cc3a46 100644 --- a/doc/reference/src/index.xml +++ b/doc/reference/src/index.xml @@ -23,6 +23,7 @@ + @@ -285,12 +286,16 @@ + + + &psa-intro; &remoting; &services; &webservices; + &wcf; diff --git a/doc/reference/src/messaging.xml b/doc/reference/src/messaging.xml index 2661b1b1..d810bc6a 100644 --- a/doc/reference/src/messaging.xml +++ b/doc/reference/src/messaging.xml @@ -44,13 +44,14 @@ SonicMQ in namespace Spring.Messaging.Sonic, - 'Jms' is sometimes used as the class prefix. + 'Jms' is sometimes used as the class prefix. (available 1.2 + RC1) Websphere MQ in namespace Spring.Messaging.Xms, 'Xms' is sometimes used as - the class prefix + the class prefix (available 1.2 RC1) @@ -1270,17 +1271,19 @@ namespace MyApp recovery-interval - The time interval between connection recovery attempts. The default is 5 seconds. - Specify as a TimeSpan value using Spring's TimeSpanConverter (e.g. 10s, 10m, 3h, etc) - + The time interval between connection recovery + attempts. The default is 5 seconds. Specify as a TimeSpan value + using Spring's TimeSpanConverter (e.g. 10s, 10m, 3h, etc) + max-recovery-time - The maximum time try reconnection attempts. The default is 10 minutes. Specify as a - TimeSpan value using Spring's TimeSpanConverter (e.g. 10s, 10m, 3h, etc) - + The maximum time try reconnection attempts. The + default is 10 minutes. Specify as a TimeSpan value using + Spring's TimeSpanConverter (e.g. 10s, 10m, 3h, etc) + @@ -1300,7 +1303,7 @@ namespace MyApp implementation. The most important resource to cache is the JMS Connection since the flow of events in the message template class (EmsTemplate) is to create/close a connection on each operation and this is an expensive - operation. + operation. Spring provides a convenience class, SingleConnectionFactory, in which the same Connection is returned on calls to CreateConnection() and diff --git a/doc/reference/src/wcf.xml b/doc/reference/src/wcf.xml new file mode 100644 index 00000000..e067ac72 --- /dev/null +++ b/doc/reference/src/wcf.xml @@ -0,0 +1,286 @@ + + + Windows Communication Foundation (WCF) + +
+ Introduction + + Spring's WCF support allows you to configure your WCF services via + dependency injection and add additional behavior to them using + Aspect-Oriented programming (AOP). + + There are two approaches in the 1.2 M1 release for configuring your + services with DI which are discussed in the following sections. One + approach creates an implementation of your service interface (a dynamic + proxy) that retrieves a configured instance of your service type from the + Spring container. This dynamic proxy is then the final service type that + is hosted. The second approach uses the extension points in WCF itself to + delegate to the Spring container to create and configure your service + type. Both approaches are discussed below. + + As it is desirable to have just one approach, we would greatly + appreciate your input regarding these two approaches as well as any other + suggestions regarding WCF support. + + For those who would like to get their feet wet right way, check out + the WcfQuickStart application in the examples directory. +
+ +
+ Configuring WCF services via Dependency Injection + + In this approach the container will creates an implementation of + your service interface (a dynamic proxy) that retrieves a configured + instance of your service type from the Spring container. This dynamic + proxy is then the final service type that is hosted. + +
+ Dependency Injection using dynamic proxies + + In this approach you develop your WCF services as you would + normally do. For example here is a sample service type taken from the + quickstart example. + + [ServiceContract(Namespace = "http://Spring.WcfQuickStart")] + public interface ICalculator + { + [OperationContract] + double Add(double n1, double n2); + [OperationContract] + double Subtract(double n1, double n2); + [OperationContract] + double Multiply(double n1, double n2); + [OperationContract] + double Divide(double n1, double n2); + [OperationContract] + string GetName(); + } + + The implementation for the methods is fairly obvious but an + additional property, SleepInSeconds, is present. This + is the property we will configure via dependency injection. Here is a + partial listing of the implementation + + public class CalculatorService : ICalculator + { + private int sleepInSeconds; + + public int SleepInSeconds + { + get { return sleepInSeconds; } + set { sleepInSeconds = value; } + } + + public double Add(double n1, double n2) + { + Thread.Sleep(sleepInSeconds*1000); + return n1 + n2; + + } + + + // additional implementation not shown for brevity + + } + + To configure this object with Spring, provide the XML + configuration metadata as shown below as you would with any Spring + managed object. + + <object id="calculator" singleton="false" type="Spring.WcfQuickStart.CalculatorService, Spring.WcfQuickStart.ServerApp"> + <property name="SleepInSeconds" value="1"/> + </object> + + + + The object must be declared as a 'prototype' object, i.e. not a + singleton, in order to interact correctly with WCF instancing. + + + To host this service type in a standalone application define an + instance of a + Spring.ServiceModel.Activation.ServiceHostFactoryObject + and set is property TargetName to the id value of + the previously defined service type. + ServiceHostFactoryObject is a Spring + IFactoryObject implementation. (See here for more + information on IFactoryObjects and their + interaction with the container.) The + ServiceHostFactoryObject will create an instance + of + Spring.ServiceModel.Activation.SpringServiceHost + that will be the ServiceHost instance associated with your service type. + This configuration for this step is shown below. + + <object id="calculatorServiceHost" type="Spring.ServiceModel.Activation.ServiceHostFactoryObject, Spring.Services"> + <property name="TargetName" value="calculator" /> + </object> + + Additional service configuration can be done declaratively in the + standard App.config file as shown below + + <system.serviceModel> + <services> + <service name="calculator" behaviorConfiguration="DefaultBehavior"> + <host> ... </host> + <endpoint> ... </endpoint> + </service> + ... + </services> + +</system.serviceModel> + + + It is important that the name of the service in the WCF + declarative configuration section match the name of the Spring object + definition + + + Spring.ServiceModel.Activation.SpringServiceHost + is where the dynamic proxy for your service type is + generated. This dynamic proxy will implement a single 'WCF' interface, + the same on that your service type implements. The implementation of the + service interface methods on the proxy will delegate to a wrapped + 'target' object which is the object instance retrieved by name from the + Spring container using the Spring API, + ApplicationContext.GetObject(name). Since the + object retrieved in this manner is fully configured, your WCF service is + as well. + + Outside of a standalone application you can also use the class + Spring.ServiceModel.Activation.ServiceHostFactory + (which inherits from + System.ServiceModel.Activation.ServiceHostFactory) + to host your services so that they can be configured via dependency + injection. To use the dynamic proxy approached described here you should + still refer to the name of the service as the name of the object + definition used to configure the service type in the Spring + container. + + There are not many disadvantages to this approach other than the + need to specify the service name as the name of the object definition in + the Spring container and to ensure that singleton=false is used in the + object definition. +
+ +
+ Dependency Injection using WCF extensibility points. + + The second approach uses the extensibility points in WCF itself to + delegate to Spring to create and configure your WCF service. This + approach was first taken (afaik) by Oran Dennison on his blog + and several other folks on the web since then. In this approach Spring + specific implementations of the WCF interfaces + System.ServiceModel.Dispatcher.IInstanceProvider + and + System.ServiceModel.Description.IServiceBehavior + are used to integrate Spring directly into the instancing of WCF + services. + + Spring's implementation of + IInstanceProvider is + Spring.ServiceModel.Dispatcher.SpringInstanceProvider. + This implementation will look for an object by type in the Spring + container and retrieve an instance configured using DI. If there is more + than one object of the type registered with the container than an + exception will be thrown. The + SpringInstanceProvider is used by a custom + service behavior class, + Spring.ServiceModel.Dispatcher.SpringServiceBehavior + where it is applied to all the service endpoints. This behavior is then + added to the custom service host + Spring.ServiceModel.Activation.SpringServiceHost + + The service type is used to locate the object in the container. In + your .svc file you specify the custom service host type and also the + type of the service. Here is an example taken from the WcfQuickStart + application that shows the use of this approach inside IIS. + + <%@ ServiceHost Language="C#" Debug="true" Service="Spring.WcfQuickStart.CalculatorService" + Factory="Spring.ServiceModel.Activation.ServiceHostFactory" %> + + + The Spring configuration for the object is shown below. + + <object id="calculator" type="Spring.WcfQuickStart.CalculatorService, App_Code" singleton="false"> + <property name="SleepInSeconds" value="1"/> + </object> + + + The object must be declared as a 'prototype' object, i.e. not a + singleton, in order to interact correctly with WCF instancing. + + + While integrating 'natively' with WCF does seem to be the most + natural approach there is one 'gotya' that needs to be investigated + further to see if there is an acceptable workaround in order for this + approach to be viable. The issue is that if the service is configured to + be a singleton, for example using + [ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)] + then the invocation of the IInstanceProvider is + short-circuited. See the notes on the MSDN class documentation here. + One workaround, which is not very appealing, is to use the PerCall + instancing mode but set the singleton attribute in the Spring + configuration to true, this way the same instance is always + returned. +
+
+ +
+ Apply AOP advice to WCF services + + In either approach to performing dependency injection you can apply + additional AOP advice to your WCF services in the same way as you have + always done in Spring. The following configuration shows how to apply some + simple performance monitoring advice to all services in the + Spring.WcfQuickStart namespace and is taken from + the QuickStart example. + + <object id="serviceOperation" type="Spring.Aop.Support.SdkRegularExpressionMethodPointcut, Spring.Aop"> + <property name="pattern" value="Spring.WcfQuickStart.*"/> + </object> + + <object id="perfAdvice" type="Spring.WcfQuickStart.SimplePerformanceInterceptor, Spring.WcfQuickStart.ServerApp"> + <property name="Prefix" value="Service Layer Performance"/> + </object> + + <aop:config> + <aop:advisor pointcut-ref="serviceOperation" advice-ref="perfAdvice"/> + </aop:config> + + The aop:config section implicitly uses Spring's autoproxying + features to add additional behavior to any objects defined in the + container that match the pointcut criteria. +
+ +
+ Creating client side proxies declaratively + + To create a client side proxy based on the use of + ChannelFactory<T>, you can use this rather ugly 'boiler plate' XML + snippit that takes uses Spring's support for calling factory methods on + object instances. + + <!-- returns ChannelFactory<ICalculator>("calculatorEndpoint").CreateChannel() --> + + <object id="serverAppCalculator" type="Spring.WcfQuickStart.ICalculator, Spring.WcfQuickStart.ClientApp" + factory-object="serverAppCalculatorChannelFactory" + factory-method="CreateChannel" /> + + <object id="serverAppCalculatorChannelFactory" + type="System.ServiceModel.ChannelFactory&lt;Spring.WcfQuickStart.ICalculator>, System.ServiceModel"> + + <constructor-arg name="endpointConfigurationName" value="serverAppCalculatorEndpoint" /> + + </object> + + + This will be shortened using a custom namespce in the 1.2 RC1 + release + +
+
\ No newline at end of file