我正在尝试使用.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请求。
底线问题:如果我更改属性,是针对整个流程还是仅更改当前线程?
答案 0 :(得分: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
每次调用创建新实例)
答案 1 :(得分:1)
我认为这里最好的方法是不使用代理类,而是将SOAP请求发送到服务器,该服务器分别完全控制您要发送和接收服务器的xml。
使用HttpWebRequest和WebResponse类来控制soap请求。根据您的逻辑更改命名空间(xmlns:xsi)..
对于e,g,: -
<?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>