diff --git a/examples/Spring/Spring.Calculator/src/Spring.Calculator.RegisterComponentServices/Spring.Calculator.EnterpriseServices.dll.spring-context.xml b/examples/Spring/Spring.Calculator/src/Spring.Calculator.RegisterComponentServices/Spring.Calculator.EnterpriseServices.dll.spring-context.xml index 3c1351c8..0fe6490e 100644 --- a/examples/Spring/Spring.Calculator/src/Spring.Calculator.RegisterComponentServices/Spring.Calculator.EnterpriseServices.dll.spring-context.xml +++ b/examples/Spring/Spring.Calculator/src/Spring.Calculator.RegisterComponentServices/Spring.Calculator.EnterpriseServices.dll.spring-context.xml @@ -1,6 +1,6 @@ - - - + + + \ No newline at end of file diff --git a/src/Spring/Spring.Services/EnterpriseServices/EnterpriseServicesExporter.cs b/src/Spring/Spring.Services/EnterpriseServices/EnterpriseServicesExporter.cs index fb712b2b..089e482b 100644 --- a/src/Spring/Spring.Services/EnterpriseServices/EnterpriseServicesExporter.cs +++ b/src/Spring/Spring.Services/EnterpriseServices/EnterpriseServicesExporter.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright 2002-2006 the original author or authors. + * Copyright 2002-2008 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -41,12 +41,84 @@ namespace Spring.EnterpriseServices /// Exports specified components as ServicedComponents. /// /// - ///

+ /// /// This class will create ServicedComponent wrapper for each of the /// specified components and register them with the Component Services. - ///

+ /// + /// + /// First you need to generate and register your components. This is done by writing a simple e.g. console application using a configuration as shown below: + /// + /// <!-- actual objects 'calculatorService' and 'simpleCalculatorService' are defined elsewhere --> + /// + /// <!-- Define the component for exporting 'calculatorService' --> + /// <object id="calculatorComponent" type="Spring.EnterpriseServices.ServicedComponentExporter, + /// Spring.Services"> + /// <property name="TargetName" value="calculatorService" /> + /// <property name="TypeAttributes"> + /// <list> + /// <object type="System.EnterpriseServices.TransactionAttribute, System.EnterpriseServices" /> + /// </list> + /// </property> + /// <property name="MemberAttributes"> + /// <dictionary> + /// <entry key="*"> + /// <list> + /// <object type="System.EnterpriseServices.AutoCompleteAttribute, System.EnterpriseServices" /> + /// </list> + /// </entry> + /// </dictionary> + /// </property> + /// </object> + /// + /// <!-- Define the component for exporting 'simpleCalculatorService' --> + /// <object id="simpleCalculatorComponent" type="Spring.EnterpriseServices.ServicedComponentExporter, + /// Spring.Services"> + /// <property name="TargetName" value="simpleCalculatorService" /> + /// </object> + /// + /// <!-- Export components into assembly and autoregister with COM+ --> + /// <object type="Spring.EnterpriseServices.EnterpriseServicesExporter, Spring.Services"> + /// <!-- assembly name to generated - will generate 'Spring.Calculator.EnterpriseServices.dll' --> + /// <property name="Assembly" value="Spring.Calculator.EnterpriseServices" /> + /// + /// <!-- + /// use Spring's ContextRegistry for managing services. If true, requires a file + /// 'Spring.Calculator.EnterpriseServices.dll.spring-context.xml' containing a + /// <spring/context /> section placed next to the generated assembly. + /// --> + /// <property name="UseSpring" value="true" /> + /// + /// <property name="ApplicationName" value="Spring Calculator Application" /> + /// <property name="ActivationMode" value="Library" /> + /// <property name="Description" value="Spring Calculator application" /> + /// <property name="Components"> + /// <list> + /// <ref object="calculatorComponent" /> + /// <ref object="simpleCalculatorComponent" /> + /// </list> + /// </property> + /// </object> + /// + /// + /// + /// To load your objectdefinitions at runtime of the components, place a configuration file next to the assembly + /// generated by the exporter, using the filename of the exported assembly, postfixing it with '.spring-context.config'. + /// Taking the example above, the file must be named 'Spring.Calculator.EnterpriseServices.dll.spring-context.xml' and look like: + /// + /// <-- --> + /// <spring> + /// <context> + /// <resource uri="Config/services.xml" /> + /// </context> + /// </spring> + /// + /// This file should point to the service object definitions you exported using with a + /// configuration as shown above. + /// ///
+ /// /// Aleksandar Seovic + /// Erich Eichinger public class EnterpriseServicesExporter : IInitializingObject, IObjectFactoryAware { #region Fields @@ -334,31 +406,31 @@ namespace Spring.EnterpriseServices /// /// /// - /// internal class SpringServicedComponent - /// { - /// protected delegate object GetObjectHandler(ServicedComponent servicedComponent, string targetName); + /// internal class SpringServicedComponent + /// { + /// protected delegate object GetObjectHandler(ServicedComponent servicedComponent, string targetName); /// - /// protected static readonly GetObjectHandler getObjectRef; + /// protected static readonly GetObjectHandler getObjectRef; /// - /// static SpringServicedComponent() - /// { - /// // first look for a local copy - /// System.Reflection.Assembly servicesAssembly; - /// string servicesAssemblyPath = Path.Combine( + /// static SpringServicedComponent() + /// { + /// // first look for a local copy + /// System.Reflection.Assembly servicesAssembly; + /// string servicesAssemblyPath = Path.Combine( /// new FileInfo(System.Reflection.Assembly.GetExecutingAssembly().Location).DirectoryName /// , "Spring.Services.dll" ); - /// servicesAssembly = System.Reflection.Assembly.LoadFrom(servicesAssemblyPath); - /// if (servicesAssembly == null) - /// { - /// // then let the normal loader handle the typeload - /// servicesAssembly = System.Reflection.Assembly.Load("Spring.Services, culture=neutral, version=x.x.x.x, publicKey=xxxxxxxx"); - /// } - /// Type componentHelperType = servicesAssembly.GetType("Spring.EnterpriseServices.ServicedComponentHelper"); - /// getObjectRef = (GetObjectHandler) Delegate.CreateDelegate(typeof(GetObjectHandler) - /// , componentHelperType.GetMethod("GetObject")); - /// } - /// } + /// servicesAssembly = System.Reflection.Assembly.LoadFrom(servicesAssemblyPath); + /// if (servicesAssembly == null) + /// { + /// // then let the normal loader handle the typeload + /// servicesAssembly = System.Reflection.Assembly.Load("Spring.Services, culture=neutral, version=x.x.x.x, publicKey=xxxxxxxx"); + /// } /// + /// Type componentHelperType = servicesAssembly.GetType("Spring.EnterpriseServices.ServicedComponentHelper"); + /// getObjectRef = (GetObjectHandler) Delegate.CreateDelegate(typeof(GetObjectHandler) + /// , componentHelperType.GetMethod("GetObject")); + /// } + /// } /// /// private Type CreateSpringServicedComponentType(ModuleBuilder module) @@ -369,10 +441,6 @@ namespace Spring.EnterpriseServices ILGenerator il = null; FieldBuilder getObjectRef = typeBuilder.DefineField("getObject", delegateType, FieldAttributes.Family | FieldAttributes.Static); - // MethodBuilder assemblyResolveHandler = GenerateOnAssemblyResolve(typeBuilder); - - // static SpringServicedComponent() { - // } ConstructorBuilder typeCtor = typeBuilder.DefineTypeInitializer(); il = typeCtor.GetILGenerator(); Label methodEnd = il.DefineLabel(); diff --git a/src/Spring/Spring.Services/EnterpriseServices/ServicedComponentContextHandler.cs b/src/Spring/Spring.Services/EnterpriseServices/ServicedComponentContextHandler.cs index 200467d1..0f2fa591 100644 --- a/src/Spring/Spring.Services/EnterpriseServices/ServicedComponentContextHandler.cs +++ b/src/Spring/Spring.Services/EnterpriseServices/ServicedComponentContextHandler.cs @@ -1,10 +1,41 @@ +#region License + +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#endregion + +#if (!NET_1_0 && !MONO) + +#region Imports + +using System.EnterpriseServices; using Spring.Context.Support; +#endregion + namespace Spring.EnterpriseServices { /// - /// + /// Handles loading of <spring/context> configuration sections for s + /// generated by . /// + /// Erich Eichinger public class ServicedComponentContextHandler : ContextHandler {} -} \ No newline at end of file +} + +#endif \ No newline at end of file diff --git a/src/Spring/Spring.Services/EnterpriseServices/ServicedComponentExporter.cs b/src/Spring/Spring.Services/EnterpriseServices/ServicedComponentExporter.cs index 152df1fa..e6373e79 100644 --- a/src/Spring/Spring.Services/EnterpriseServices/ServicedComponentExporter.cs +++ b/src/Spring/Spring.Services/EnterpriseServices/ServicedComponentExporter.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright 2002-2007 the original author or authors. + * Copyright 2002-2008 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -40,13 +40,16 @@ namespace Spring.EnterpriseServices /// wrapper around target class. /// /// - ///

+ /// /// Instances of this class should be used as elements in the Components /// list of the class, which will - /// register them with COM+ Services. - ///

+ /// register them with COM+ Services. For a full description on how to export + /// and use services with COM+, see the reference. + /// ///
+ /// /// Aleksandar Seovic + /// Erich Eichinger public class ServicedComponentExporter : IInitializingObject, IObjectNameAware { #region Fields diff --git a/src/Spring/Spring.Services/EnterpriseServices/ServicedComponentHelper.cs b/src/Spring/Spring.Services/EnterpriseServices/ServicedComponentHelper.cs index 91e43353..59e38d78 100644 --- a/src/Spring/Spring.Services/EnterpriseServices/ServicedComponentHelper.cs +++ b/src/Spring/Spring.Services/EnterpriseServices/ServicedComponentHelper.cs @@ -18,17 +18,16 @@ #endregion +#if (!NET_1_0 && !MONO) + #region Imports using System; -using System.Configuration; using System.EnterpriseServices; using System.IO; using System.Reflection; using System.Xml; -using Spring.Context; using Spring.Context.Support; -using Spring.Reflection.Dynamic; using ConfigXmlDocument = Spring.Util.ConfigXmlDocument; #endregion @@ -36,7 +35,8 @@ using ConfigXmlDocument = Spring.Util.ConfigXmlDocument; namespace Spring.EnterpriseServices { /// - /// + /// This class supports s exported using . + /// and must never be used directly. /// /// Erich Eichinger public class ServicedComponentHelper @@ -50,8 +50,9 @@ namespace Spring.EnterpriseServices } /// + /// Reads in the 'xxx.spring-context.xml' configuration file associated with the specified . + /// See for an in-depth description on how to export and configure COM+ components. /// - /// private static void EnsureComponentContextRegistryInitialized(ServicedComponent component) { if (isInitialized) return; @@ -61,10 +62,14 @@ namespace Spring.EnterpriseServices if (isInitialized) return; isInitialized = true; + // this is to ensure, that assemblies place next to the component assembly can be loaded + // even when they are not strong named. AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve); FileInfo componentAssemblyFile = new FileInfo(component.GetType().Assembly.Location); componentDirectory = componentAssemblyFile.Directory.FullName; + // switch to component assembly's directory (affects resolving relative paths during context instantiation!) Environment.CurrentDirectory = componentDirectory; + // read in config file ConfigXmlDocument configDoc = new ConfigXmlDocument(); FileInfo configFile = new FileInfo(componentAssemblyFile.FullName + ".spring-context.xml"); if (configFile.Exists) @@ -74,6 +79,10 @@ namespace Spring.EnterpriseServices ServicedComponentContextHandler handler = new ServicedComponentContextHandler(); lock (ContextRegistry.SyncRoot) { + // it might accidentially have happend, that the contextregistry has already + // been initialized using the client application's app.config configuration. + // Most of the time this doesn't make sense to read a configuration from a + // different AppDomain, thus we read in our own config file. ContextRegistry.Clear(); handler.Create(null, null, configNode); } @@ -81,7 +90,7 @@ namespace Spring.EnterpriseServices } } - static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) + private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) { string name = args.Name.Split(',')[0]; Assembly assembly = Assembly.LoadFrom(Path.Combine(componentDirectory, name + ".dll")); @@ -89,16 +98,15 @@ namespace Spring.EnterpriseServices } /// + /// Called by a exported by + /// to obtain a reference to the service it proxies. /// - /// - /// - /// public static object GetObject(ServicedComponent sender, string targetName) { EnsureComponentContextRegistryInitialized(sender); return ContextRegistry.GetContext().GetObject(targetName); - // return null; } - } -} \ No newline at end of file +} + +#endif \ No newline at end of file