| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256 |
- //-----------------------------------------------------------------------------
- // Copyright (c) Microsoft Corporation. All rights reserved.
- //-----------------------------------------------------------------------------
- using System.Collections.Generic;
- using System.ServiceModel.Channels;
- using System.ServiceModel;
- using System.ServiceModel.Dispatcher;
- using System.CodeDom;
- using System.Globalization;
- using System.Text;
- using System.Xml.Serialization;
- using System.CodeDom.Compiler;
- using System.Runtime.Serialization;
- namespace System.ServiceModel.Description
- {
- class XmlSerializerOperationGenerator : IOperationBehavior, IOperationContractGenerationExtension
- {
- OperationGenerator operationGenerator;
- Dictionary<MessagePartDescription, PartInfo> partInfoTable;
- Dictionary<OperationDescription, XmlSerializerFormatAttribute> operationAttributes = new Dictionary<OperationDescription, XmlSerializerFormatAttribute>();
- XmlCodeExporter xmlExporter;
- SoapCodeExporter soapExporter;
- XmlSerializerImportOptions options;
- CodeNamespace codeNamespace;
- internal XmlSerializerOperationGenerator(XmlSerializerImportOptions options)
- {
- operationGenerator = new OperationGenerator();
- this.options = options;
- this.codeNamespace = GetTargetCodeNamespace(options);
- partInfoTable = new Dictionary<MessagePartDescription, PartInfo>();
- }
- static CodeNamespace GetTargetCodeNamespace(XmlSerializerImportOptions options)
- {
- CodeNamespace targetCodeNamespace = null;
- string clrNamespace = options.ClrNamespace ?? string.Empty;
- foreach (CodeNamespace ns in options.CodeCompileUnit.Namespaces)
- {
- if (ns.Name == clrNamespace)
- {
- targetCodeNamespace = ns;
- }
- }
- if (targetCodeNamespace == null)
- {
- targetCodeNamespace = new CodeNamespace(clrNamespace);
- options.CodeCompileUnit.Namespaces.Add(targetCodeNamespace);
- }
- return targetCodeNamespace;
- }
- internal void Add(MessagePartDescription part, XmlMemberMapping memberMapping, XmlMembersMapping membersMapping, bool isEncoded)
- {
- PartInfo partInfo = new PartInfo();
- partInfo.MemberMapping = memberMapping;
- partInfo.MembersMapping = membersMapping;
- partInfo.IsEncoded = isEncoded;
- partInfoTable[part] = partInfo;
- }
- public XmlCodeExporter XmlExporter
- {
- get
- {
- if (this.xmlExporter == null)
- {
- this.xmlExporter = new XmlCodeExporter(this.codeNamespace, this.options.CodeCompileUnit, this.options.CodeProvider,
- this.options.WebReferenceOptions.CodeGenerationOptions, null);
- }
- return xmlExporter;
- }
- }
- public SoapCodeExporter SoapExporter
- {
- get
- {
- if (this.soapExporter == null)
- {
- this.soapExporter = new SoapCodeExporter(this.codeNamespace, this.options.CodeCompileUnit, this.options.CodeProvider,
- this.options.WebReferenceOptions.CodeGenerationOptions, null);
- }
- return soapExporter;
- }
- }
- OperationGenerator OperationGenerator
- {
- get { return this.operationGenerator; }
- }
- internal Dictionary<OperationDescription, XmlSerializerFormatAttribute> OperationAttributes
- {
- get { return operationAttributes; }
- }
- void IOperationBehavior.Validate(OperationDescription description)
- {
- }
- void IOperationBehavior.AddBindingParameters(OperationDescription description, BindingParameterCollection parameters)
- {
- }
- void IOperationBehavior.ApplyDispatchBehavior(OperationDescription description, DispatchOperation dispatch) { }
- void IOperationBehavior.ApplyClientBehavior(OperationDescription description, ClientOperation proxy) { }
- static object contractMarker = new object();
- // Assumption: gets called exactly once per operation
- void IOperationContractGenerationExtension.GenerateOperation(OperationContractGenerationContext context)
- {
- if (context == null)
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("context");
- if (partInfoTable != null && partInfoTable.Count > 0)
- {
- Dictionary<XmlMembersMapping, XmlMembersMapping> alreadyExported = new Dictionary<XmlMembersMapping, XmlMembersMapping>();
- foreach (MessageDescription message in context.Operation.Messages)
- {
- foreach (MessageHeaderDescription header in message.Headers)
- GeneratePartType(alreadyExported, header, header.Namespace);
- MessageBodyDescription body = message.Body;
- bool isWrapped = (body.WrapperName != null);
- if (OperationFormatter.IsValidReturnValue(body.ReturnValue))
- GeneratePartType(alreadyExported, body.ReturnValue, isWrapped ? body.WrapperNamespace : body.ReturnValue.Namespace);
- foreach (MessagePartDescription part in body.Parts)
- GeneratePartType(alreadyExported, part, isWrapped ? body.WrapperNamespace : part.Namespace);
- }
- }
- XmlSerializerOperationBehavior xmlSerializerOperationBehavior = context.Operation.Behaviors.Find<XmlSerializerOperationBehavior>() as XmlSerializerOperationBehavior;
- if (xmlSerializerOperationBehavior == null)
- return;
- XmlSerializerFormatAttribute xmlSerializerFormatAttribute = (xmlSerializerOperationBehavior == null) ? new XmlSerializerFormatAttribute() : xmlSerializerOperationBehavior.XmlSerializerFormatAttribute;
- OperationFormatStyle style = xmlSerializerFormatAttribute.Style;
- operationGenerator.GenerateOperation(context, ref style, xmlSerializerFormatAttribute.IsEncoded, new WrappedBodyTypeGenerator(context), new Dictionary<MessagePartDescription, ICollection<CodeTypeReference>>());
- context.ServiceContractGenerator.AddReferencedAssembly(typeof(System.Xml.Serialization.XmlTypeAttribute).Assembly);
- xmlSerializerFormatAttribute.Style = style;
- context.SyncMethod.CustomAttributes.Add(OperationGenerator.GenerateAttributeDeclaration(context.Contract.ServiceContractGenerator, xmlSerializerFormatAttribute));
- AddKnownTypes(context.SyncMethod.CustomAttributes, xmlSerializerFormatAttribute.IsEncoded ? SoapExporter.IncludeMetadata : XmlExporter.IncludeMetadata);
- DataContractSerializerOperationGenerator.UpdateTargetCompileUnit(context, this.options.CodeCompileUnit);
- }
- private void AddKnownTypes(CodeAttributeDeclarationCollection destination, CodeAttributeDeclarationCollection source)
- {
- foreach (CodeAttributeDeclaration attribute in source)
- {
- CodeAttributeDeclaration knownType = ToKnownType(attribute);
- if (knownType != null)
- {
- destination.Add(knownType);
- }
- }
- }
- // Convert [XmlInclude] or [SoapInclude] attribute to [KnownType] attribute
- private CodeAttributeDeclaration ToKnownType(CodeAttributeDeclaration include)
- {
- if (include.Name == typeof(SoapIncludeAttribute).FullName || include.Name == typeof(XmlIncludeAttribute).FullName)
- {
- CodeAttributeDeclaration knownType = new CodeAttributeDeclaration(new CodeTypeReference(typeof(ServiceKnownTypeAttribute)));
- foreach (CodeAttributeArgument argument in include.Arguments)
- {
- knownType.Arguments.Add(argument);
- }
- return knownType;
- }
- return null;
- }
- private void GeneratePartType(Dictionary<XmlMembersMapping, XmlMembersMapping> alreadyExported, MessagePartDescription part, string partNamespace)
- {
- if (!partInfoTable.ContainsKey(part))
- return;
- PartInfo partInfo = partInfoTable[part];
- XmlMembersMapping membersMapping = partInfo.MembersMapping;
- XmlMemberMapping memberMapping = partInfo.MemberMapping;
- if (!alreadyExported.ContainsKey(membersMapping))
- {
- if (partInfo.IsEncoded)
- SoapExporter.ExportMembersMapping(membersMapping);
- else
- XmlExporter.ExportMembersMapping(membersMapping);
- alreadyExported.Add(membersMapping, membersMapping);
- }
- CodeAttributeDeclarationCollection additionalAttributes = new CodeAttributeDeclarationCollection();
- if (partInfo.IsEncoded)
- SoapExporter.AddMappingMetadata(additionalAttributes, memberMapping, false/*forceUseMemberName*/);
- else
- XmlExporter.AddMappingMetadata(additionalAttributes, memberMapping, partNamespace, false/*forceUseMemberName*/);
- part.BaseType = GetTypeName(memberMapping);
- operationGenerator.ParameterTypes.Add(part, new CodeTypeReference(part.BaseType));
- operationGenerator.ParameterAttributes.Add(part, additionalAttributes);
- }
- internal string GetTypeName(XmlMemberMapping member)
- {
- string typeName = member.GenerateTypeName(options.CodeProvider);
- // If it is an array type, get the array element type name instead
- string comparableTypeName = typeName.Replace("[]", null);
- if (codeNamespace != null && !string.IsNullOrEmpty(codeNamespace.Name))
- {
- foreach (CodeTypeDeclaration typeDecl in codeNamespace.Types)
- {
- if (typeDecl.Name == comparableTypeName)
- {
- typeName = codeNamespace.Name + "." + typeName;
- }
- }
- }
- return typeName;
- }
- class PartInfo
- {
- internal XmlMemberMapping MemberMapping;
- internal XmlMembersMapping MembersMapping;
- internal bool IsEncoded;
- }
- internal class WrappedBodyTypeGenerator : IWrappedBodyTypeGenerator
- {
- OperationContractGenerationContext context;
- public WrappedBodyTypeGenerator(OperationContractGenerationContext context)
- {
- this.context = context;
- }
- public void ValidateForParameterMode(OperationDescription operation)
- {
- }
- public void AddMemberAttributes(XmlName messageName, MessagePartDescription part, CodeAttributeDeclarationCollection importedAttributes, CodeAttributeDeclarationCollection typeAttributes, CodeAttributeDeclarationCollection fieldAttributes)
- {
- if (importedAttributes != null)
- fieldAttributes.AddRange(importedAttributes);
- }
- public void AddTypeAttributes(string messageName, string typeNS, CodeAttributeDeclarationCollection typeAttributes, bool isEncoded)
- {
- // we do not need top-level attibutes for the encoded SOAP
- if (isEncoded)
- return;
- XmlTypeAttribute xmlType = new XmlTypeAttribute();
- xmlType.Namespace = typeNS;
- typeAttributes.Add(OperationGenerator.GenerateAttributeDeclaration(context.Contract.ServiceContractGenerator, xmlType));
- }
- }
- }
- }
|