| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520 |
- //
- // ServiceContractGenerator.cs
- //
- // Author:
- // Atsushi Enomoto <[email protected]>
- //
- // Copyright (C) 2005 Novell, Inc. http://www.novell.com
- //
- // Permission is hereby granted, free of charge, to any person obtaining
- // a copy of this software and associated documentation files (the
- // "Software"), to deal in the Software without restriction, including
- // without limitation the rights to use, copy, modify, merge, publish,
- // distribute, sublicense, and/or sell copies of the Software, and to
- // permit persons to whom the Software is furnished to do so, subject to
- // the following conditions:
- //
- // The above copyright notice and this permission notice shall be
- // included in all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- //
- using System;
- using System.CodeDom;
- using System.Collections.Generic;
- using System.Collections.ObjectModel;
- using System.Configuration;
- using System.Reflection;
- using System.Runtime.Serialization;
- using System.ServiceModel;
- using System.ServiceModel.Channels;
- using System.ServiceModel.Configuration;
- using System.Xml.Schema;
- using System.Xml.Serialization;
- using ConfigurationType = System.Configuration.Configuration;
- using QName = System.Xml.XmlQualifiedName;
- namespace System.ServiceModel.Description
- {
- public class ServiceContractGenerator
- {
- CodeCompileUnit ccu;
- ConfigurationType config;
- Collection<MetadataConversionError> errors
- = new Collection<MetadataConversionError> ();
- Dictionary<string,string> nsmappings
- = new Dictionary<string,string> ();
- Dictionary<ContractDescription,Type> referenced_types
- = new Dictionary<ContractDescription,Type> ();
- ServiceContractGenerationOptions options;
- Dictionary<QName, QName> imported_names = null;
- public ServiceContractGenerator ()
- : this (null, null)
- {
- }
- public ServiceContractGenerator (CodeCompileUnit ccu)
- : this (ccu, null)
- {
- }
- public ServiceContractGenerator (ConfigurationType config)
- : this (null, config)
- {
- }
- public ServiceContractGenerator (CodeCompileUnit ccu, ConfigurationType config)
- {
- if (ccu == null)
- this.ccu = new CodeCompileUnit ();
- else
- this.ccu = ccu;
- this.config = config;
- Options |= ServiceContractGenerationOptions.ChannelInterface |
- ServiceContractGenerationOptions.ClientClass;
- }
- public ConfigurationType Configuration {
- get { return config; }
- }
- public Collection<MetadataConversionError> Errors {
- get { return errors; }
- }
- public Dictionary<string,string> NamespaceMappings {
- get { return nsmappings; }
- }
- public ServiceContractGenerationOptions Options {
- get { return options; }
- set { options = value; }
- }
- public Dictionary<ContractDescription,Type> ReferencedTypes {
- get { return referenced_types; }
- }
- public CodeCompileUnit TargetCompileUnit {
- get { return ccu; }
- }
- [MonoTODO]
- public void GenerateBinding (Binding binding,
- out string bindingSectionName,
- out string configurationName)
- {
- throw new NotImplementedException ();
- }
- #region Service Contract Type
- // Those implementation classes are very likely to be split
- // into different classes.
- [MonoTODO]
- public CodeTypeReference GenerateServiceContractType (
- ContractDescription contractDescription)
- {
- CodeNamespace cns = GetNamespace (contractDescription.Namespace);
- imported_names = new Dictionary<QName, QName> ();
- try {
- return ExportInterface (contractDescription, cns);
- } finally {
- if ((Options & ServiceContractGenerationOptions.ClientClass) != 0)
- GenerateProxyClass (contractDescription, cns);
- if ((Options & ServiceContractGenerationOptions.ChannelInterface) != 0)
- GenerateChannelInterface (contractDescription, cns);
- }
- }
- CodeNamespace GetNamespace (string ns)
- {
- if (ns == null)
- ns = String.Empty;
- foreach (CodeNamespace cns in ccu.Namespaces)
- if (cns.Name == ns)
- return cns;
- CodeNamespace ncns = new CodeNamespace ();
- //ncns.Name = ns;
- ccu.Namespaces.Add (ncns);
- return ncns;
- }
- CodeTypeDeclaration GetTypeDeclaration (CodeNamespace cns, string name)
- {
- foreach (CodeTypeDeclaration type in cns.Types)
- if (type.Name == name)
- return type;
- return null;
- }
- void GenerateProxyClass (ContractDescription cd, CodeNamespace cns)
- {
- string name = cd.Name + "Client";
- if (name [0] == 'I')
- name = name.Substring (1);
- CodeTypeDeclaration type = GetTypeDeclaration (cns, name);
- if (type != null)
- return; // already imported
- CodeTypeReference clientBase = new CodeTypeReference (typeof (ClientBase<int>).GetGenericTypeDefinition ());
- clientBase.TypeArguments.Add (new CodeTypeReference (cd.Name));
- type = new CodeTypeDeclaration (name);
- cns.Types.Add (type);
- type.TypeAttributes = TypeAttributes.Public;
- type.BaseTypes.Add (clientBase);
- type.BaseTypes.Add (new CodeTypeReference (cd.Name));
- // .ctor()
- CodeConstructor ctor = new CodeConstructor ();
- ctor.Attributes = MemberAttributes.Public;
- type.Members.Add (ctor);
- // .ctor(string endpointConfigurationName)
- ctor = new CodeConstructor ();
- ctor.Attributes = MemberAttributes.Public;
- ctor.Parameters.Add (
- new CodeParameterDeclarationExpression (
- new CodeTypeReference (typeof (string)), "endpointConfigurationName"));
- ctor.BaseConstructorArgs.Add (
- new CodeArgumentReferenceExpression ("endpointConfigurationName"));
- type.Members.Add (ctor);
- // .ctor(string endpointConfigurationName, string remoteAddress)
- ctor = new CodeConstructor ();
- ctor.Attributes = MemberAttributes.Public;
- ctor.Parameters.Add (
- new CodeParameterDeclarationExpression (
- new CodeTypeReference (typeof (string)), "endpointConfigurationName"));
- ctor.Parameters.Add (
- new CodeParameterDeclarationExpression (
- new CodeTypeReference (typeof (string)), "remoteAddress"));
- ctor.BaseConstructorArgs.Add (
- new CodeArgumentReferenceExpression ("endpointConfigurationName"));
- ctor.BaseConstructorArgs.Add (
- new CodeArgumentReferenceExpression ("remoteAddress"));
- type.Members.Add (ctor);
- // .ctor(string endpointConfigurationName, EndpointAddress remoteAddress)
- ctor = new CodeConstructor ();
- ctor.Attributes = MemberAttributes.Public;
- ctor.Parameters.Add (
- new CodeParameterDeclarationExpression (
- new CodeTypeReference (typeof (string)), "endpointConfigurationName"));
- ctor.Parameters.Add (
- new CodeParameterDeclarationExpression (
- new CodeTypeReference (typeof (EndpointAddress)), "remoteAddress"));
- ctor.BaseConstructorArgs.Add (
- new CodeArgumentReferenceExpression ("endpointConfigurationName"));
- ctor.BaseConstructorArgs.Add (
- new CodeArgumentReferenceExpression ("remoteAddress"));
- type.Members.Add (ctor);
- // .ctor(Binding,EndpointAddress)
- ctor = new CodeConstructor ();
- ctor.Attributes = MemberAttributes.Public;
- ctor.Parameters.Add (
- new CodeParameterDeclarationExpression (
- new CodeTypeReference (typeof (Binding)), "binding"));
- ctor.Parameters.Add (
- new CodeParameterDeclarationExpression (
- new CodeTypeReference (typeof (EndpointAddress)), "endpoint"));
- ctor.BaseConstructorArgs.Add (
- new CodeArgumentReferenceExpression ("binding"));
- ctor.BaseConstructorArgs.Add (
- new CodeArgumentReferenceExpression ("endpoint"));
- type.Members.Add (ctor);
- // service contract methods
- AddImplementationMethods (type, cd);
- }
- void GenerateChannelInterface (ContractDescription cd, CodeNamespace cns)
- {
- string name = cd.Name + "Channel";
- CodeTypeDeclaration type = GetTypeDeclaration (cns, name);
- if (type != null)
- return;
- type = new CodeTypeDeclaration ();
- type.Name = name;
- type.TypeAttributes = TypeAttributes.Interface | TypeAttributes.Public;
- cns.Types.Add (type);
-
- type.BaseTypes.Add (ExportInterface (cd, cns));
- type.BaseTypes.Add (new CodeTypeReference (typeof (System.ServiceModel.IClientChannel)));
- }
- CodeTypeReference ExportInterface (ContractDescription cd, CodeNamespace cns)
- {
- CodeTypeDeclaration type = GetTypeDeclaration (cns, cd.Name);
- if (type != null)
- return new CodeTypeReference (type.Name);
- type = new CodeTypeDeclaration ();
- type.TypeAttributes = TypeAttributes.Interface;
- type.TypeAttributes |= TypeAttributes.Public;
- cns.Types.Add (type);
- type.Name = cd.Name;
- CodeAttributeDeclaration ad =
- new CodeAttributeDeclaration (
- new CodeTypeReference (
- typeof (ServiceContractAttribute)));
- ad.Arguments.Add (new CodeAttributeArgument ("Namespace", new CodePrimitiveExpression (cd.Namespace)));
- type.CustomAttributes.Add (ad);
- AddOperationMethods (type, cd);
- return new CodeTypeReference (type.Name);
- }
- void AddOperationMethods (CodeTypeDeclaration type, ContractDescription cd)
- {
- foreach (OperationDescription od in cd.Operations) {
- CodeMemberMethod cm = new CodeMemberMethod ();
- type.Members.Add (cm);
- cm.Name = od.Name;
- if (od.SyncMethod != null) {
- ExportParameters (cm, od.SyncMethod.GetParameters ());
- cm.ReturnType = new CodeTypeReference (od.SyncMethod.ReturnType);
- } else {
- ExportMessages (od.Messages, cm, false);
- }
- // [OperationContract (Action = "...", ReplyAction = "..")]
- CodeAttributeDeclaration ad =
- new CodeAttributeDeclaration (
- new CodeTypeReference (
- typeof (OperationContractAttribute)));
- foreach (MessageDescription md in od.Messages) {
- if (md.Direction == MessageDirection.Input)
- ad.Arguments.Add (new CodeAttributeArgument ("Action", new CodePrimitiveExpression (md.Action)));
- else
- ad.Arguments.Add (new CodeAttributeArgument ("ReplyAction", new CodePrimitiveExpression (md.Action)));
- }
- cm.CustomAttributes.Add (ad);
- }
- }
- void ExportParameters (CodeMemberMethod method, ParameterInfo [] parameters)
- {
- foreach (ParameterInfo pi in parameters)
- method.Parameters.Add (
- new CodeParameterDeclarationExpression (
- new CodeTypeReference (pi.ParameterType),
- pi.Name));
- }
- void AddImplementationMethods (CodeTypeDeclaration type, ContractDescription cd)
- {
- foreach (OperationDescription od in cd.Operations) {
- CodeMemberMethod cm = new CodeMemberMethod ();
- type.Members.Add (cm);
- cm.Name = od.Name;
- cm.Attributes = MemberAttributes.Public
- | MemberAttributes.Final;
- CodeExpression [] args = null;
- if (od.SyncMethod != null) {
- ParameterInfo [] pars = od.SyncMethod.GetParameters ();
- ExportParameters (cm, pars);
- cm.ReturnType = new CodeTypeReference (od.SyncMethod.ReturnType);
- args = new CodeExpression [pars.Length];
- int i = 0;
- foreach (ParameterInfo pi in pars)
- args [i ++] = new CodeArgumentReferenceExpression (pi.Name);
- } else {
- args = ExportMessages (od.Messages, cm, true);
- }
- CodeExpression call = new CodeMethodInvokeExpression (
- new CodePropertyReferenceExpression (
- new CodeBaseReferenceExpression (),
- "Channel"),
- cm.Name,
- args);
- if (cm.ReturnType.BaseType == "System.Void")
- cm.Statements.Add (new CodeExpressionStatement (call));
- else
- cm.Statements.Add (new CodeMethodReturnStatement (call));
- }
- }
- private CodeExpression[] ExportMessages (MessageDescriptionCollection messages, CodeMemberMethod method, bool return_args)
- {
- CodeExpression [] args = null;
- foreach (MessageDescription md in messages) {
- if (md.Direction == MessageDirection.Output) {
- if (md.Body.ReturnValue != null) {
- ExportDataContract (md.Body.ReturnValue.XmlTypeMapping);
- method.ReturnType = new CodeTypeReference (md.Body.ReturnValue.TypeName.Name);
- }
- continue;
- }
- if (return_args)
- args = new CodeExpression [md.Body.Parts.Count];
- MessagePartDescriptionCollection parts = md.Body.Parts;
- for (int i = 0; i < parts.Count; i++) {
- ExportDataContract (parts [i].XmlTypeMapping);
- method.Parameters.Add (
- new CodeParameterDeclarationExpression (
- new CodeTypeReference (parts [i].TypeName.Name),
- parts [i].Name));
- if (return_args)
- args [i] = new CodeArgumentReferenceExpression (parts [i].Name);
- }
- }
- return args;
- }
- #endregion
- [MonoTODO]
- public CodeTypeReference GenerateServiceEndpoint (
- ServiceEndpoint endpoint,
- out ChannelEndpointElement channelElement)
- {
- throw new NotImplementedException ();
- }
-
- private void ExportDataContract (XmlTypeMapping mapping)
- {
- if (mapping == null)
- return;
- QName qname = new QName (mapping.TypeName, mapping.Namespace);
- if (imported_names.ContainsKey (qname))
- return;
- CodeNamespace cns = new CodeNamespace ();
- XmlCodeExporter xce = new XmlCodeExporter (cns);
- xce.ExportTypeMapping (mapping);
- List <CodeTypeDeclaration> to_remove = new List <CodeTypeDeclaration> ();
-
- //Process the types just generated
- //FIXME: Iterate and assign the types to correct namespaces
- //At the end, add all those namespaces to the ccu
- foreach (CodeTypeDeclaration type in cns.Types) {
- string ns = GetXmlNamespace (type);
- if (ns == null)
- //FIXME: do what here?
- continue;
- QName type_name = new QName (type.Name, ns);
- if (imported_names.ContainsKey (type_name)) {
- //Type got reemitted, so remove it!
- to_remove.Add (type);
- continue;
- }
- imported_names [type_name] = type_name;
- type.Comments.Clear ();
- //Custom Attributes
- type.CustomAttributes.Clear ();
- if (type.IsEnum)
- continue;
-
- type.CustomAttributes.Add (
- new CodeAttributeDeclaration (
- new CodeTypeReference ("System.CodeDom.Compiler.GeneratedCodeAttribute"),
- new CodeAttributeArgument (new CodePrimitiveExpression ("System.Runtime.Serialization")),
- new CodeAttributeArgument (new CodePrimitiveExpression ("3.0.0.0"))));
-
- type.CustomAttributes.Add (
- new CodeAttributeDeclaration (
- new CodeTypeReference ("System.Runtime.Serialization.DataContractAttribute")));
- //BaseType and interface
- type.BaseTypes.Add (new CodeTypeReference (typeof (object)));
- type.BaseTypes.Add (new CodeTypeReference ("System.Runtime.Serialization.IExtensibleDataObject"));
- foreach (CodeTypeMember mbr in type.Members) {
- CodeMemberProperty p = mbr as CodeMemberProperty;
- if (p == null)
- continue;
- if ((p.Attributes & MemberAttributes.Public) == MemberAttributes.Public) {
- //FIXME: Clear all attributes or only XmlElementAttribute?
- p.CustomAttributes.Clear ();
- p.CustomAttributes.Add (new CodeAttributeDeclaration (
- new CodeTypeReference ("System.Runtime.Serialization.DataMemberAttribute")));
- p.Comments.Clear ();
- }
- }
- //Fields
- CodeMemberField field = new CodeMemberField (
- new CodeTypeReference ("System.Runtime.Serialization.ExtensionDataObject"),
- "extensionDataField");
- field.Attributes = MemberAttributes.Private | MemberAttributes.Final;
- type.Members.Add (field);
- //Property
- CodeMemberProperty prop = new CodeMemberProperty ();
- prop.Type = new CodeTypeReference ("System.Runtime.Serialization.ExtensionDataObject");
- prop.Name = "ExtensionData";
- prop.Attributes = MemberAttributes.Public | MemberAttributes.Final;
- //Get
- prop.GetStatements.Add (new CodeMethodReturnStatement (
- new CodeFieldReferenceExpression (
- new CodeThisReferenceExpression (),
- "extensionDataField")));
- //Set
- prop.SetStatements.Add (new CodeAssignStatement (
- new CodeFieldReferenceExpression (
- new CodeThisReferenceExpression (),
- "extensionDataField"),
- new CodePropertySetValueReferenceExpression ()));
- type.Members.Add (prop);
- }
- foreach (CodeTypeDeclaration type in to_remove)
- cns.Types.Remove (type);
- ccu.Namespaces.Add (cns);
- }
-
- private string GetXmlNamespace (CodeTypeDeclaration type)
- {
- foreach (CodeAttributeDeclaration attr in type.CustomAttributes) {
- if (attr.Name == "System.Xml.Serialization.XmlTypeAttribute" ||
- attr.Name == "System.Xml.Serialization.XmlRootAttribute") {
- foreach (CodeAttributeArgument arg in attr.Arguments)
- if (arg.Name == "Namespace")
- return ((CodePrimitiveExpression)arg.Value).Value as string;
- //Could not find Namespace arg!
- return null;
- }
- }
-
- return null;
- }
- }
- }
|