Lav dine egne Proxy klasser - nemt og ligetil
For lang tid siden var jeg til noget Microsoft gøjl, hvor Jakob Tikjøb Andersen snakkede om DynamicProxy. Tiden er gået, og det er nu blevet dagen, hvor jeg tænkte jeg kunne bruge dette framework til at implementere noget caching på min blog.
DynamicProxy er en dynamisk proxy generator (flot oversat, ikke?). Ved en proxy klasse menes der en klasse som har én opgave i livet, og det er at ligne en anden klasse, og så kalde den anden klasses metoder.
Et fint lille eksempel kunne være, at man gerne ville have en log over hver gang denne klasse blev kaldt, samt at den noterede hvor lang tid metoden tog. Man kunne tjekke sikkerhed, osv. - brug din fantasi :)
Forestil dig at du har en klasse som har 100 metoder. Hver metode vil du gerne gøre noget bestemt ved - evt. ændre parametrene, eller som i vores eksempel logge. Skulle du lave dette manuelt, ville du nok være doven, og kun vælge at gøre det de vigtigste steder, og du ville have noget kode som er svær at vedligeholde.
DynamicProxy er en af de værktøjer som kan hjælpe dig af med dette. Jeg valgte at skrive denne blog post, da det overraskede mig hvor let, og ligetil det er at bruge. Faktisk tog det mig vel 2min at implementere et simpelt eksempel, og det overraskede mig alligevel noget, da jeg forestille mig at der sikkert skulle store XML filer til, for at få det til at virke.
Først gik jeg ind og hentede DynamicProxy, jeg tilføjede derefter DLL filerne til mit lille test projekt, samt sørgede for at jeg havde en reference til System.Web (Umildbart så kræver DynamicProxy System.Web) Andre siger dette ikke er nødvendigt med System.Web, så hvorfor jeg lige skulle bruge den, kan jeg ikke svare på.
Jeg lavede derefter jordens mest simple interface og klasse:
public interface IDataProvider
{
void DoStuff();
}
public class DataProvider : IDataProvider
{
public void DoStuff() {
Console.WriteLine("Done stuff");
}
}
Jeg har behov for at have en klasse, som står for at lave mit logging arbejde. Dette heder i DynamicProxy for en Interceptor:
public class LogInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation) {
Console.WriteLine("Before");
invocation.Proceed();
Console.WriteLine("After");
}
}
Denne metode bliver simpelthen kaldt, hver gang en metode i mit interface bliver kaldt. Du kan se at jeg bare skriver noget ud til console, men jeg kunne nemt have gjort alt muligt fancy.
Derefter tog jeg min Main metode og skrev flg.:
class Program
{
static void Main(string[] args) {
ProxyGenerator p = new ProxyGenerator();
IDataProvider provider = p.CreateInterfaceProxyWithTarget<IDataProvider>
(new DataProvider(), new LogInterceptor());
provider.DoStuff();
Console.ReadLine();
}
}
Det jeg gør er simpelhen at lave en ny generator, og så bede den om dynamic at lave en proxy klasse der implementere mit interface, og som har min konkrete klasse som target. Jeg kobler også min nye LogInterceptor på, og vola - så er der proxy på min DataProvider:
Before
Done stuff
After
Det var altså alt hvad der skulle til, for at lave mig en proxy klasse. Har du allerede løst koblet objekter i dit projekt, så er det altså meget let at lave en proxy, som kan fuldføre ens arbejde som alle dine metoder skal udføre.
Mulighederne er mange, og jeg har bare vist jer jordens mest simple eksempel.