views:

639

answers:

4

Hi, i've been playing around with Attributes over web services, and i've seen that The SoapHttpClientProtocol class need to define a WebServiceBinding Attribute.

Watching this question there seems one cannot modify the attributes on runtime, how can I achieve a dynamic web service invocation changing this attribute on runtime? is it possible?

[Edit] I'm searching for an approach to do a dynamic invoke "generic style", rather to modify the WebServiceBinding attribute.

This is, in a nutshell, my class:

using System.Web.Services;
using System.Web.Services.Protocols;

namespace Whatever {
    [WebServiceBinding(Name = "", Namespace = "")]
    public class WebServiceInvoker : SoapHttpClientProtocol {
     public WebServiceInvoker(string url, string ns, string bindingName) {

      ChangeNamespace(ns);
      ChangeBinding(bindingName);
      Url = url;
      // credentials, etc
    }
     public void ChangeNamespace(string ns) {
      var att = GetType().GetCustomAttributes(typeof (WebServiceBindingAttribute), true);   
      if (att.Length > 0) {
       // doesn't work
       ((WebServiceBindingAttribute)att[0]).Namespace = ns;
      }
     }
     private void ChangeBinding(string bindingName) {
      var att = GetType().GetCustomAttributes(typeof(WebServiceBindingAttribute), true);

      if (att.Length > 0) {
       // doesn't work
       ((WebServiceBindingAttribute)att[0]).Name = bindingName;
      }
     }
     public object[] MakeInvoke(string method, object[] args) {
      var res = Invoke(method, method);
      return res;
     }

     public TRet InvokeFunction<TRet>(string method) {
      //Funcion<T1, T2, T3, TRet>
      var res = Invoke(method, null);
      return MyUtils.ForceCast<TRet>(res);
     }
     public TRet InvokeFunction<T1, TRet>(string method, T1 par1) {
      //Funcion<T1, T2, T3, TRet>
      var args = new object[] { par1 };
      var res = Invoke(method, args);
      return MyUtils.ForceCast<TRet>(res);
     }
     public TRet InvokeFunction<T1, T2, TRet>(string method, T1 par1, T2 par2) {
      //Funcion<T1, T2, T3, TRet>
      var args = new object[] { par1, par2 };
      var res = Invoke(method, args);
      return MyUtils.ForceCast<TRet>(res);
     }
     public TRet InvokeFunction<T1, T2, T3, TRet>(string method, T1 par1, T2 par2, T3 par3) {
      //Funcion<T1, T2, T3, TRet>
      var args = new object[] {par1, par2, par3};
      var res = Invoke(method, args);
      return MyUtils.ForceCast<TRet>(res);
     }

     public void InvokeAction(string metodo) {
      //Funcion<T1, T2, T3, TRet>
      Invoke(method, null);
     }
     public void InvokeAction<T1>(string method, T1 par1) {
      //Funcion<T1, T2, T3, TRet>
      var args = new object[] { par1 };
      Invoke(method, args);
     }
     public void InvokeAction<T1, T2>(string method, T1 par1, T2 par2) {
      //Funcion<T1, T2, T3, TRet>
      var args = new object[] { par1, par2 };
      Invoke(method, args);
     }
     public void InvokeAction<T1, T2, T3>(string method, T1 par1, T2 par2, T3 par3) {
      //Funcion<T1, T2, T3, TRet>
      var args = new object[] { par1, par2, par3 };
      Invoke(method, args);
     }
    }
}

[Edit] I would like to call my class like so:

var miProxy = new WebServiceInvoker("http://webServiceLocation", "ns", "Binding");
var res = miProxy.InvokeFunction<string, string, Entity>("MyWebMethod", stringPar1, stringPar2);
+2  A: 

You cannot change attributes at runtime. They are just metadata in the IL code and if you query a attribute an instance of the specified attribute class is created and returned. So the actual attribute instances do not exist until you query them.

It might be possible to modify the assembly using reflection but I am not sure and this is probably not a thing you like to try.

Daniel Brückner
+1  A: 

I'm not exactly sure what you're trying to accomplish here... are you trying to create a web service which supports invocation of arbitrary methods by the caller? If so, here is an example of that in practice: Creating a dynamic Web service to simplify code

Rex M
The solution you provided is good, i like it, however I was searching for a way to combine generic delegates with web services invocations, i mean, for calling a webService just knowing its url, don't know if it is possible.
Jhonny D. Cano -Leftware-
+1  A: 

As you stated, you cannot modify an attribute at runtime.

The only way to achieve the affect of addding/removing/changing an attribute at runtime is to create a new type that wraps the actual type. Runtime proxy classes have overhead (development complexity and performance), though, and are rarely ever worth it in production code.

I would, however, look in to the correctness of the statement:

The SoapHttpClientProtocol class need to define a WebServiceBinding Attribute.

Microsoft usually gives you at least two ways to skin the cat. I'm willing to bet that the above is not categorically true. There's probably another way to accomplish what you're trying to do.

What I'm trying to say is: you might be barking up the wrong tree by pursuing the runtime attribute route.

Michael Meadows
+1  A: 

There is another really good example of this at Crows Programming. It describes a class that allows you to call arbitrary messages on any web service. It's actually pretty slick. Hope it helps.