不同系统利用Web Service交互项目中涉及到的一些知识点

最近在做一个项目,需要利用WebService进行不同系统间的交互,其中学习到了很多技术上的知识。很多东西还是会在真正的实践中发现问题,进而去解决的。接下去我会列举一些。

场景

系统A在外网上,系统B在内网,A需要发送消息到B,在B中根据发送的符合XML格式的raw字符串在B中做一些操作。因为A在外网,在A上enable了SSL,并且A的服务器上部署了一个类似proxy的webservice,只是做一些验证,真正的事情是在B中完成。于是也部署了一个webservice在A上。

1。数据结构只有出现在方法的参数,返回值上,才会在客户端生成代理类,这个代理类不包括原来数据类型中的方法。

原本有一个类型我想在A和B的webservice上都用,于是两个项目都引用了这个Model的DLL(A的webserive一个project,B

也一个,Model一个),但是编译会错,因为A会报这个类型在两个Namespace里都存在(因为A引用了B的webservice,A右引用了这个Model的DLL。会有一个类似的****.proxy.的namespace和一个dll自己的namespace)。于是不需要这个Model的DLL了,也可以移去这个project,A只要引用这个Webservice,自然生成了代理类。

方法并不会在代理类里生成,为了封装性的话可以通过partial类来解决这个问题。

2.IComparable

有时候我们一些数据类型会以集合的形式存在,比如List<MyType>,这个list需要根据Type李某一个字段排序的,我们可以让这个类型继承IComparable接口,如果从效率考虑可以继承范型的接口

class MyType:IComparable<MyType>
{
  public int CompareTo(MyType)
  {

    return ******;
  }
}

 

然后只要调用自己的Sort()方法就能自行排序了

3。Webservice对于有些参数类型,比如dictionary,hashtable等

只能自己定义类型满足类似的功能

[Serializable]
public class SMSFKeyValuePair
{
    public string Key { get; set; }
    public decimal Value { get; set; }
}

4。如果你想通过浏览器测试,比如给QA一个测试页面。webservice中你要传递一个xml格式的字符串的,因为安全原因,runtime会block这种request

需要自己定一个custom validator

public class CustomRequestValidator : RequestValidator
{
        //force web service accept xml string type parameter and skip the request validation 
        protected override bool IsValidRequestString(HttpContext context, string value, RequestValidationSource requestValidationSource, string collectionKey, out int validationFailureIndex)
        {
            // Set a default value for the out parameter.
            validationFailureIndex = -1;
            return true; 
        }
 }

同时配置webconfig

<httpRuntime requestValidationType="Mercer.SMSF.SMSFExternalWebSerivce.CustomRequestValidator.CustomRequestValidator" />

5。ASPNET自带IP lockdown的功能,只要在webconfig里面配置一下就行了

<system.webServer>
    <security>
      <ipSecurity allowUnlisted="false">
        <clear/>
        <add ipAddress="127.0.0.1" allowed="true"/><!-- allow requests from the local machine -->
        <add ipAddress="123.200.169.186" allowed="true"/>
        <add ipAddress="220.157.70.222" allowed="true"/>
      </ipSecurity>
    </security>
    <modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>

6。Webservice的异步问题

A的webserivce的method1里面做了一些事情后会调用B的webservice的method2,而且method1需要在很短的时间里返回,但是method2又很费时,那怎么办?本来觉得只要在method1里面调用mehod2的异步的那个方法,method1就很快返回到client端了,经测试不可行。还是会等mthod2完成后返回,跟同步效果一样了。。。就单独一个webserive方法调用采用异步的那个方法应该能马上返回,因为这里有两层了,所以并不行。后来发现再method1里起一个线程去调用method2,能达到这个预期的效果。前段时间看了点.net的异步编程,于是试着用了下

//start a async task to generate result package 
Task.Factory.StartNew((o) =>
            Method2(o), mytype)
            .ContinueWith((t) =>
            {
              ExceptionManager.Publish(t.Exception);
            },
            TaskContinuationOptions.OnlyOnFaulted);

7。xml 序列化

当我们需要返回给客户端一个xml格式的字符串的时候,我们该怎么做。我们可以定义一个类型,结构类似于xml。最后序列化这个对象就可以了。

那如何自定义这个类型的属性在生成的xml字符串里是node还是innertext还是attribute呢,还有如何自定义nodename,attributename呢。可以利用System.Xml.Serialization下很多attribute来定义

XmlRoot,XmlElement,XmlAttribute,XmlText,那些不需要序列化到xmlstring里的可以用XmlIgnore.

还有个问题有时需要一个CDATA类型的,可是.net框架目前没有支持这种类型怎么办,可以自己来

[Serializable]
    public class CDATA : IXmlSerializable
    {
        private string text;

        public CDATA()
        {
        }

        public CDATA(string text)
        {
            this.text = text;
        }

        public System.Xml.Schema.XmlSchema GetSchema()
        {
            return null;
        }

        public void ReadXml(System.Xml.XmlReader reader)
        {
            this.text = reader.ReadString();
        }

        public void WriteXml(System.Xml.XmlWriter writer)
        {
            writer.WriteCData(this.text);
        }
    }

比如Comment字段可能需要序列化到CDATA里,先定一个Comment属性,还有个CDATAComment属性,序列化时ignore Comment这个属性

private string comment;
[XmlIgnore]
public string Comment
{
    get
    {
        return comment;
    }
    set
    {
        comment = value;
        CDataComment = new CDATA(comment);
    }
}
[XmlElement(ElementName = "comment", Type = typeof(CDATA))]
public CDATA CDataComment { get; set; }

然后我需要序列化这个类型的对象,我这里练了下扩展方法,而且因为这种xml序列化需求很多地方都要用到,我写了个范型的方法

public static class PackageExtension
{
        public static string OutputXML<T> (this T instance) where T:IMyXmlSerializable
        {
            StringBuilder sb = new StringBuilder();
            Type type = typeof(T);
            XmlSerializer serializer = new XmlSerializer(type);
            XmlSerializerNamespaces xmlns = new XmlSerializerNamespaces();
            xmlns.Add(String.Empty, String.Empty);
            XmlWriterSettings settings = new XmlWriterSettings();
            settings.Indent = true;
            using (XmlWriter xmlWriter = XmlWriter.Create(sb))
            {
                serializer.Serialize(xmlWriter, instance, xmlns);
            }
            return sb.ToString();
        }
}

你可能会问IMyXmlSerializable是什么,此时只是一个标识,也就是说只有继承这个接口的类型才能调用这个扩展方法,不加这个限制的话,所有类都能调用了,自然会报错,于是只要在我需要xml序列化的类上标记继承这个接口就行了。这个接口其实是空的。

public interface IMyXmlSerializable
{
}

8。Webconfig protocols设置问题

VS跑起来webservice都能测试,可是部署上去不行,请看:

http://support.microsoft.com/kb/815150

http://msdn.microsoft.com/en-us/library/b2c0ew36%28v=vs.71%29.aspx

ms在本地加了个HttpPostLocalhost

 

 

 

 

posted @ 2012-08-16 12:26  nickycookie  阅读(630)  评论(4编辑  收藏  举报