AutoFac WCF proxy with changing ClientCredentials -


i'm writing wcf service , using autofac wcf integration di. have weird situation have proxy service requires credentials. credentials change based on parameters coming in can't set values when i'm setting container , done it.

public class myservice : imyservice {     private isomeotherservice _client;     public myservice(isomeotherservice client)     {         _client = client;     }      public response somecall(somedata data)     {         // how set clientcredentials here, without casting concrete implementation         _client.makeacall();     } } 

what's best way set credentials on proxy without having cast known type or channelbase. i'm trying avoid because in unit tests i'm mocking out proxy interface casting 1 of types fail.

any thoughts?

you can it, it's not straightforward, , have change design logic of "decide , set credentials" pulled out of myservice class.

first, let's define rest of classes in scenario can see come together.

we have isomeotherservice interface, i've modified can see credentials getting set @ end. have return string instead of being void. i've got implementation of someotherservice has credential get/set (which clientcredentials in wcf). looks this:

public interface isomeotherservice {   string makeacall(); }  public class someotherservice : isomeotherservice {   // "credentials" here stand-in wcf "clientcredentials."   public string credentials { get; set; }    // returns credentials used can validate things   // wired up. don't have in "real life."   public string makeacall()   {     return this.credentials;   } } 

notice credentials property not exposed interface can see how work without casting interface concrete type.

next have imyservice interface , associated request/response objects somecall operation show in question. (in question have somedata it's same idea, went different naming convention me keep straight input vs. output.)

public class somecallrequest {   // number value we'll use determine   // set of client credentials.   public int number { get; set; } }  public class somecallresponse {   // response include credentials used, passed   // call isomeotherservice.   public string credentialsused { get; set; } }  public interface imyservice {   somecallresponse somecall(somecallrequest request); } 

the interesting part there data we're using choose set of credentials number in request. whatever want be, using number here makes code little simpler.

here's starts getting more complex. first need familiar 2 autofac things:

we'll make use of both of concepts here.

the implementation of myservice gets switched take factory take in int , return instance of isomeotherservice. when want reference other service, execute function , pass in number determine client credentials.

public class myservice : imyservice {   private func<int, isomeotherservice> _clientfactory;    public myservice(func<int, isomeotherservice> clientfactory)   {     this._clientfactory = clientfactory;   }    public somecallresponse somecall(somecallrequest request)   {     var client = this._clientfactory(request.number);     var response = client.makeacall();     return new somecallresponse { credentialsused = response };   } } 

the real key there func<int, isomeotherservice> dependency. we'll register isomeotherservice , autofac automatically create factory takes in int , returns isomeotherservice us. no real special work required... though registration little complex.

the last piece register lambda isomeotherservice instead of simpler type/interface mapping. lambda typed int parameter , we'll use determine/set client credentials.

var builder = new containerbuilder(); builder.register((c, p) =>   {     // in wcf, more going call     // channelfactory<t>.createchannel(), ease     // here we'll new up:     var service = new someotherservice();      // magic: incoming int parameter -     // func<int, isomeotherservice> pass     // in when called.     var data = p.typedas<int>();      // our simple "credentials" tell whether     // passed in or odd number. yours     // way more complex, looking config,     // resolving sort of "credential factory"     // current context (the "c" parameter in lambda),     // or else want.     if(data % 2 == 0)     {       service.credentials = "even";     }     else     {       service.credentials = "odd";     }     return service;   }) .as<isomeotherservice>();  // , registration of consuming service here. builder.registertype<myservice>().as<imyservice>(); var container = builder.build(); 

ok, have registration taking in integer , returning service instance, can use it:

using(var scope = container.beginlifetimescope()) {   var myservice = scope.resolve<imyservice>();   var request = new somecallrequest { number = 2 };   var response = myservice.somecall(request);    // write "credentials = even" @ console   // because passed in number , registration   // lambda executed set credentials.   console.writeline("credentials = {0}", response.credentialsused); } 

boom! credentials got set without having cast base class.

design changes:

  • the credential "set" operation got moved out of consuming code. if don't want cast base class in consuming code, won't have choice pull credential "set" operation out. logic right in lambda; or put in separate class gets used inside lambda; or handle onactivated event , little magic there (i didn't show - exercise left reader). "tie together" bit has somewhere in component registration (the lambda, event handler, etc.) because that's point @ still have concrete type.
  • the credentials set lifetime of proxy. it's not if have single proxy in consuming code set different credentials before execute each operation. can't tell question if that's how have it, but... if that's case, need different proxy each call. may mean want dispose of proxy after you're done it, so you'll need @ using owned<t> (which make factory func<int, owned<t>>) or run memory leak if services long-lived singletons.

there other ways this, too. create own custom factory; handle onactivated event mentioned; use autofac.extras.dynamicproxy2 library create dynamic proxy intercepts calls wcf service , sets credentials before allowing call proceed... brainstorm other ways, idea. what posted here how i'd it, , @ least point in direction need go.


Comments

Popular posts from this blog

monitor web browser programmatically in Android? -

Shrink a YouTube video to responsive width -

wpf - PdfWriter.GetInstance throws System.NullReferenceException -