Dassis etwas mühsam, weil es um Codes in VB geht, die auf Arbeit sind (und ich krankgeschrieben).
Aber ich habs jetzt mal vom Prinzip aussm Kopf glaub ziemlich korrekt hingebastelt.
Also auf ARbeit haben wir eine Anwendung, die ca. 50 InterfaceMember in 10 WcfServices konsumiert, und das ist eine wahre "DoRepeatYourself"-Orgie, schlimmer noch, die Selbstwiderholungen sind teilweise auch noch inkorrekt implementiert. (hysterisch gewachsener Code).
Also wenn man nur einen besch... String abrufen will muss man folgende Übung absolvieren:
static string GetFoo() {
// dazu Logging, Localisation, Errorhandling, response-Header-Auswertung - in immer derselben Implementierung
using (var myClient = new ServiceClient())
using (var scope = new OperationContextScope(myClient.InnerChannel)) {
OperationContext.Current.OutgoingMessageProperties["Autentication"] = _AutenticationToken;
return myClient.foo().Data;
}
}
Wie gesagt (im Comment angedeutet), das eigentliche Code-Gebrabbel ist hier weggelassen, realiter ists das 3-fache, und ist immer dasselbe.
Das Gebrabbel habich nun isoliert - der Pattern heisst glaub "Function höherer Ordnung einführen":
static string GetFoo2() {
return Execute((ServiceClient clnt) => clnt.foo().Data);
}
static TResult Execute<TService, TResult>(Func<TService, TResult> fnc) where TService : IDisposable, new() {
// dazu Logging, Localisation, Errorhandling, response-Header-Auswertung - einmal implementiert, und richtig
using (var myClient = new TService()) {
IClientChannel chnl = GetChannelFromClient(myClient);
using (var scope = new OperationContextScope(chnl)) {
OperationContext.Current.OutgoingMessageProperties["Autentication"] = _AutenticationToken;
return fnc(myClient);
}
}
}
Wie du siehst - GetFoo2 macht jetzt nur noch, was man denkt was GetFoo2 im Kern zu machen hat - alles annere ist an einem Punkt konzentriert und sauber.
Bisserl unsauber halt noch das GetChannelFromClient(), weil das hampelt - wie du dir auch gedacht hast - mit Reflection rum, bzw. mit dynamic.
Jo, und da bin ich bisserl frustriert, dass ich die TypEinschränkung nicht so formulieren kann, dass ich normal auf myClient.InnerChannel zugreifen kann.
Weil eigentlich sind ja alle notwendigen TypInformationen gegeben.
Es ist also einerseits ein konkretes Problem, andererseits ein abstraktes: Es scheint mir ein Mangel der Sprache zu sein, weil prinzipiell wäre hier doch die Möglichkeit gegeben, auch Polymorphie bereitzustellen.
Nämlich die nicht-generischen Member eines generischen Typs könnte man doch eiglich zugreifbar machen, auch ohne dass der konkrete TypParameter bekannt ist.
Man kanns auch als DesignFehler der ServiceBase<T> - Klasse sehen: Täte die von einer nichtgenerischen ServiceBase erben, welche den .InnerChannel veröffentlichte, wäre ich ebenfalls nu der Notwendigkeit enthoben herumzureflecten.