代码改变世界

wcf/web service 编码

2011-04-28 18:51  乱世文章  阅读(148)  评论(0编辑  收藏  举报
using System;
using System.CodeDom;
using System.IO;
using System.Text;
using System.Web.Services.Configuration;
using System.Web.Services.Description;
using System.Web.Services.Protocols;
using System.Xml.Serialization;
 
// The YMLAttribute allows a developer to specify that the YML SOAP
// extension run on a per-method basis.  The disabled property
// turns reversing the XML on and off. 

[AttributeUsage(AttributeTargets.Method, AllowMultiple=false)]
public class YMLAttribute : SoapExtensionAttribute 
{
  int priority = 0;
  bool disabled = false;
       
  public YMLAttribute() : this(false) {}
  public YMLAttribute(bool disabled) 
  {
     this.disabled = disabled;
  }
      
  public override Type ExtensionType 
  {
    get { return typeof(YMLExtension); }
  }
  public override int Priority 
  {
    get { return priority; }
    set { priority = value; }
  }

  public bool Disabled 
  { 
    get { return disabled; }
    set { disabled = value; }
  }
}

public class YMLExtension : SoapExtension 
{
  bool disabled = false;
  Stream oldStream;
  Stream newStream;

  public override object GetInitializer(LogicalMethodInfo methodInfo,
                                        SoapExtensionAttribute attribute)
  {
    YMLAttribute attr = attribute as YMLAttribute;
    if (attr != null) return attr.Disabled;
       return false;
  }

  public override object GetInitializer(Type serviceType) 
  {
        return false;
  }

  public override void Initialize(object initializer) 
  {
     if (initializer is Boolean) disabled = (bool)initializer;
  }

  public override Stream ChainStream(Stream stream) 
  {
     if (disabled) return base.ChainStream(stream);
     oldStream = stream;
     newStream = new MemoryStream();
     return newStream;
  }

  public override void ProcessMessage(SoapMessage message) 
  {
    if (disabled) return;
    switch (message.Stage) 
    {
      case SoapMessageStage.BeforeSerialize:
        Encode(message);
        break;
      case SoapMessageStage.AfterSerialize:
        newStream.Position = 0;
        Reverse(newStream, oldStream);
        break;
      case SoapMessageStage.BeforeDeserialize:
        Decode(message);
        break;
      case SoapMessageStage.AfterDeserialize:
        break;
    }
  }        
  void Encode(SoapMessage message) 
  {
     message.ContentType = "text/yml";
  }

  void Decode(SoapMessage message) 
  {
   if (message.ContentType != "text/yml") 
     throw new Exception("invalid content type:" + message.ContentType);
   Reverse(oldStream, newStream);
   newStream.Position = 0;
   message.ContentType = "text/xml";
  }

  void Reverse(Stream from, Stream to) 
  {
    TextReader reader = new StreamReader(from);
    TextWriter writer = new StreamWriter(to);
    string line;
    while ((line = reader.ReadLine()) != null) 
    {
      StringBuilder builder = new StringBuilder();
      for (int i = line.Length - 1; i >= 0; i--) 
      {
        builder.Append(line[i]);
      }
      writer.WriteLine(builder.ToString());
    }
    writer.Flush();
  }
}

// The YMLReflector class is part of the YML SDFE; it is
// called during the service description generation process.
public class YMLReflector : SoapExtensionReflector 
{
  public override void ReflectMethod() 
  {
    ProtocolReflector reflector = ReflectionContext;
    YMLAttribute attr = (YMLAttribute)reflector.Method.GetCustomAttribute(
                        typeof(YMLAttribute));
    // If the YMLAttribute has been applied to this Web service
    // method, adds the XML defined in the YMLOperationBinding class.
    if (attr != null) 
    {
      YMLOperationBinding yml = new YMLOperationBinding();
      yml.Reverse = !(attr.Disabled);
      reflector.OperationBinding.Extensions.Add(yml);
    }
  }
}
  
// The YMLImporter class is part of the YML SDFE; it is called when
// a proxy class is generated for each Web service method the proxy
// class communicates with.  The class checks whether the service
// description contains the XML that this SDFE adds to a service
// description.  If it exists, then the YMLExtension is applied to the
// method in the proxy class.
public class YMLImporter : SoapExtensionImporter 
{
  public override void ImportMethod(CodeAttributeDeclarationCollection
                                    metadata)
 {
    SoapProtocolImporter importer = ImportContext;
   // Checks whether the XML specified in the YMLOperationBinding is in
   // the service description.
   YMLOperationBinding yml = (YMLOperationBinding)
       importer.OperationBinding.Extensions.Find(
       typeof(YMLOperationBinding));
   if (yml != null)
   {
     // Only applies the YMLAttribute to the method when the XML should
     // be reversed.
     if (yml.Reverse)
     {
       CodeAttributeDeclaration attr = new CodeAttributeDeclaration(
            typeof(YMLAttribute).FullName);
       attr.Arguments.Add(new CodeAttributeArgument(new
         CodePrimitiveExpression(true)));
       metadata.Add(attr);
     }
   }
 }
}

// The YMLOperationBinding class is part of the YML SDFE; it is the
// class that is serialized into XML and placed in the service
// description.
[XmlFormatExtension("action", YMLOperationBinding.YMLNamespace,
                    typeof(OperationBinding))]
[XmlFormatExtensionPrefix("yml", YMLOperationBinding.YMLNamespace)]
public class YMLOperationBinding : ServiceDescriptionFormatExtension 
{
   private Boolean reverse;
   public const string YMLNamespace = "http://www.contoso.com/yml";

   [XmlElement("Reverse")]
   public Boolean Reverse 
   {
     get { return reverse; }
     set { reverse = value; }
   }
}