1

我正在尝试使用来自 .NET 的第三方 SOAP API。像往常一样,我生成了一个 C# 代理类来调用它,一切正常。

然后我与供应商交谈,发现为了在租户(数据库)之间切换,我必须指定不同的 XML 命名空间。问题是,命名空间被烘焙到代理代码中。匿名版本:

[System.CodeDom.Compiler.GeneratedCodeAttribute("wsdl", "2.0.50727.42")]
[System.Web.Services.WebServiceBindingAttribute(
    Name="eStrangeAPI", Namespace="urn:wsTenantSpecific")]
public partial class eTimeWSService : System.Web.Services.Protocols.SoapHttpClientProtocol {
    [System.Web.Services.Protocols.SoapDocumentMethodAttribute("", 
        RequestNamespace="urn:wsTenantSpecific:eStrange",
        ResponseNamespace="urn:wsClientSpecificNamespace:eStrange", ...]
    ...
    public string methodCall(ref Param param) {
        ...
    }

所以我需要wsTenantSpecific根据当前使用的帐户更改命名空间。我可以获取类上的属性并即时修改它们......

var attr = ((WebServiceBindingAttribute[])
    typeof( eTimeWSService ).GetCustomAttributes(
    typeof( WebServiceBindingAttribute ), false ))[ 0 ];
attr.Namespace = "urn:wsADifferentNameSpace";

...但我担心这是线程安全的。我们可以同时连接多个帐户,在同一进程的不同线程上运行 ASP.NET 请求。

底线问题:如果我更改一个属性,它是针对整个进程还是仅针对当前线程进行更改?

4

2 回答 2

2

底线问题:如果我更改一个属性,它是针对整个进程还是仅针对当前线程进行更改?

两者都不。两者兼而有之。这取决于。

属性对象在有人请求之前实际上并不存在,即使那样,也不能保证每次请求时都会返回相同的实例 - 因此更改属性上的值很可能对另一个检查该属性的调用者没有任何影响属性。但是,在某些情况下,属性实例可能会被缓存,在这种情况下,您可能会获得相同的实例,因此它可能很重要。但!在谈论序列化程序和类似工具时,很有可能正在使用元编程和缓存策略,因此它实际上并不是每次都检查属性 - 实际上,它很可能在第一次需要时就发出了一些动态代码到,现在没有任何重新审视反射方面的意图。

我个人会寻找另一种方法。改变属性不是尝试这样做的好方法。

例如,这写hello/ hello(更改丢失):

using System;
class FooAttribute : Attribute {
    public FooAttribute(string bar) {
        Bar = bar;
    }
    public string Bar { get; set; }
}
[Foo("hello")]
class Program {
    static void Main() {
        WriteFooBar<Program>();
        var d = (FooAttribute)Attribute.GetCustomAttribute(
            typeof(Program), typeof(FooAttribute));
        d.Bar = "world";
        WriteFooBar<Program>();
    }
    static void WriteFooBar<T>() {
        var bar = ((FooAttribute)Attribute.GetCustomAttribute(
            typeof(T), typeof(FooAttribute))).Bar;
        Console.WriteLine(bar);
    }
}

并且这个类似的代码写hello/ world(更改被保留):

using System;
using System.ComponentModel;
class FooAttribute : Attribute {
    public FooAttribute(string bar) {
        Bar = bar;
    }
    public string Bar { get; set; }
}
[Foo("hello")]
class Program {
    static void Main() {
        WriteFooBar<Program>();
        var d = (FooAttribute)TypeDescriptor.GetAttributes(typeof(Program))[
            typeof(FooAttribute)];
        d.Bar = "world";
        WriteFooBar<Program>();
    }
    static void WriteFooBar<T>() {
        var bar = ((FooAttribute)TypeDescriptor.GetAttributes(typeof(Program))[
            typeof(FooAttribute)]).Bar;
        Console.WriteLine(bar);
    }
}

(因为TypeDescriptor.GetAttributes缓存每种类型的实际属性实例,而Attribute.GetCustomAttribute每次调用都会创建新实例)

于 2013-07-01T13:39:49.910 回答
1

我认为这里最好的方法不是使用代理类,而是将 SOAP 请求发送到服务器,这可以完全控制您想要分别发送和接收服务器的 xml。

使用 HttpWebRequest 和 WebResponse 类来控制soap请求。根据您的逻辑更改名称空间(xmlns:xsi)。

例如:-

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
      Your Request goes here....
  </soap:Body>
</soap:Envelope>

请参阅无代理网络服务客户端

于 2013-07-01T13:53:47.520 回答