【问题标题】:What is the scope of a .NET class attribute change?.NET 类属性更改的范围是什么?
【发布时间】:2013-07-01 13:34:53
【问题描述】:

我正在尝试使用来自 .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 请求。

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

【问题讨论】:

    标签: c# asp.net .net soap wsdl


    【解决方案1】:

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

    两者都没有。两者兼而有之。视情况而定。

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

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

    例如,这写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 为每个调用创建了新实例)

    【讨论】:

    • 谢谢马克。我以为我需要尝试不同的方法,但希望有一种简单的方法。
    【解决方案2】:

    我认为这里最好的方法不是使用代理类,而是将 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>
    

    请看proxy less web service client

    【讨论】:

    • 我想过......这个 API 是超级丑陋的 :-)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-06
    • 1970-01-01
    相关资源
    最近更新 更多