Un task scheduler în .NET sau cum să aleg o componentă open source

De curând, la un mic pet project la care lucram de ceva vreme, am avut nevoie de un task scheduller – după câteva încercări de a meșteri ceva pe cont propriu, mi-am dat seama că în ultimii nouă ani am mai facut asa ceva (în aplicații comerciale) de vreo două ori, și nu e trivial. Cum din motive evidente nu mai pot folosi acele componente în afara firmei, și cum nu am timp sa reinventez roata, am început să ma uit în jur după ceva gata făcut.

Ne fiind vorba să fac vreun profit din jucaria de aplicație la care lucram, zgârcit de felul meu, m-am apucat să mă uit după ceva gratis.
Totul pleacă de la requirements, și în acest caz ele ar fi ceva de genul:
- un task scheduller simplu care, într-o aplicație server-side (să zicem Windows service sau Azure worker role, nu contează), care să-mi permită să:
- execut periodic diverse acțiuni/taskuri
- eventual în paralel
- taskurile să poata fi definite în .NET ca parte a proiectului (nu executabile externe)
- definiția și starea taskurilor să poată fi persistată
- dacă aplicația e oprită temporar să știe să reia execuția
- simplu de folosit, fără deployment complex, cât mai independent de componente externe
Ce nu intră la requirements:
- workflows și alte minuni

După câteva căutari am găsit ceva ce sună interesant: Quartz.NET.

Hai să vedem dacă merită folosit:

- poate fi instalat usor?

PM> Install-Package Quartz
'Common.Logging (≥ 1.2.0)' not installed. Attempting to retrieve dependency from source...
Done.
Successfully installed 'Common.Logging 1.2.0'.
Successfully installed 'Quartz 1.0.3'.
Successfully added 'Common.Logging 1.2.0' to TestQuartzNet.
Successfully added 'Quartz 1.0.3' to TestQuartzNet.

.. se pare că da

- e open-source? – da (http://quartznet.sourceforge.net/license.html)
- are documentație și un tutorial? – așa se pare (http://quartznet.sourceforge.net/tutorial/index.html)
- s-au obosit să creeze un changelog și release notes după fiecare versiune? – yep (https://github.com/quartznet/quartznet/blob/master/changelog.txt)
- au un forum/mailing list activ, ceva de genul, unde pot pune întrebări? – da (http://groups.google.com/group/quartznet)
- proiectul mai e activ? – da, din câte se vede pe Github

Next, o scurtă privire peste calitatea componentei:
- au unit teste? da: https://github.com/quartznet/quartznet/tree/master/src/Quartz.Tests.Unit
- ceva integration tests? asa se pare: https://github.com/quartznet/quartznet/tree/master/src/Quartz.Tests.Integration
- au reinventat roata fără să se uite în jur? Se pare că nu – componenta e un port în .NET a unei componente de success din Java, Quartz, de la aceeași sursă ce produce Terracota – un nume cunoscut în lumea Java.
Ne place sau nu, .NET a intrat un pic mai târziu în joc, și unele din cele mai bune și de success componente (open source) din lumea .NET sunt portate sau inspirate din componente similare Java: NHibernate, NUnit, CruiseControl.NET, Spring.Net etc. – ceea ce nu e rău – o arhitectură sau idee de success, acolo unde e cazul, nu merită recreată doar de dragul originalității.
La componente comerciale povestea e puțin diferită, normal.

Dar destul cu vorbăria, ar trebui să văd un pic de cod.
O metodă simplă de a vedea dacă o componentă e funcțională, dar și pentru a vedea niște exemple de cum trebuie folosită, e să arunc o privire peste unit teste. Cum sunt leneș și nu vreau să compilez sursele, am “extras” proiectul cu unit teste din .zip-ul de la http://sourceforge.net/projects/quartznet/files/quartznet/Quartz.NET%201.0.3/, l-am mutat în soluția proprie, și am modificat referințele a.î. să pointeze la assembly-urile aduse cu NuGet.
Un quick run la toate testele, și arată mulțumitor deocamdată:
123 passed, 1 failed, 16 skipped (see ‘Task List’), took 10.57 seconds (NUnit 2.4).

Comparat cu numarul de teste, ruleaza suficient de rapid, ceea ce e un indiciu ca s-ar putea să fie ok scrise.

Cum scopul meu nu e să fac un code review, și plecând de la unit teste risc să mă pierd în diverse scenarii avansate, nu ar strica niște exemple la obiect. Din fericire, autorii s-au obosit să creeze și așa ceva: Quartz.Examples:

Quartz examples run

Exemplele sunt bine comentate, chiar dacă codul e self-describing (un alt criteriu important – ideal codul nu ar trebui să aibă nevoie de multe comentarii pentru a putea fi înteles:

  1. public class SimpleJob : IJob
  2.     {
  3.         private static ILog _log = LogManager.GetLogger(typeof(SimpleJob));
  4.         ///<summary>
  5.         /// Empty constructor for job initilization.
  6.         ///</summary>
  7.         public SimpleJob()
  8.         {
  9.         }
  10.         ///<summary>
  11.         /// Called by the <see cref=”IScheduler” /> when a
  12.         ///<see cref=”Trigger” /> fires that is associated with
  13.         /// the <see cref=”IJob” />.
  14.         ///</summary>
  15.         public virtual void  Execute(JobExecutionContext context)
  16.         {
  17.             // This job simply prints out its job name and the
  18.             // date and time that it is running
  19.             string jobName = context.JobDetail.FullName;
  20.             _log.Info(string.Format(“SimpleJob says: {0} executing at {1}”, jobName, DateTime.Now.ToString(“r”)));
  21.         }
  22.     }

Și niște exemple:

  1. ILog log = LogManager.GetLogger(typeof (SimpleTriggerExample));
  2. // First we must get a reference to a scheduler
  3. ISchedulerFactory sf = new StdSchedulerFactory();
  4. IScheduler sched = sf.GetScheduler();
  5. // jobs can be scheduled before sched.start() has been called
  6. // get a “nice round” time a few seconds in the future…
  7. DateTime ts = TriggerUtils.GetNextGivenSecondDate(null, 15);
  8.  
  9. // job6 will run indefinitely, every 50 seconds
  10. JobDetail job = new JobDetail(“job6″, “group1″, typeof (SimpleJob));
  11. trigger = new SimpleTrigger(“trigger6″, “group1″, “job6″, “group1″, ts, null,
  12.                             SimpleTrigger.RepeatIndefinitely, TimeSpan.FromSeconds(50));
  13. ft = sched.ScheduleJob(job, trigger);
  14. log.Info(string.Format(“{0} will run at: {1} and repeat: {2} times, every {3} seconds”,
  15.     job.FullName, ft.ToString(“r”), trigger.RepeatCount, trigger.RepeatInterval.TotalSeconds));
  16. log.Info(“——- Starting Scheduler —————-”);
  17. // All of the jobs have been added to the scheduler, but none of the jobs
  18. // will run until the scheduler has been started
  19. sched.Start();
  20.   
  21. // jobs can also be scheduled after start() has been called…
  22. // job7 will repeat 20 times, repeat every five minutes
  23. job = new JobDetail(“job7″, “group1″, typeof (SimpleJob));
  24. trigger = new SimpleTrigger(“trigger7″, “group1″, “job7″, “group1″, ts, null, 20, TimeSpan.FromMinutes(5));
  25. ft = sched.ScheduleJob(job, trigger);
  26. log.Info(string.Format(“{0} will run at: {1} and repeat: {2} times, every {3} seconds”,
  27.     job.FullName, ft.ToString(“r”), trigger.RepeatCount, trigger.RepeatInterval.TotalSeconds));
  28. // jobs can be fired directly… (rather than waiting for a trigger)
  29. job = new JobDetail(“job8″, “group1″, typeof (SimpleJob));
  30. job.Durable = (true);
  31. sched.AddJob(job, true);
  32. log.Info(“‘Manually’ triggering job8…”);
  33. sched.TriggerJob(“job8″, “group1″);
  34. sched.Shutdown(true);

Pare destul de clean, clasele au responsabilități clare: IJob – acțiunea/taskul custom în sine, JobDetail – diverse atribute asociate cu instanța unui job
Trigger – definește un “schedule”, modul în care un job va fi executat (când, cat de des etc.)
Scheduller – responsabil pentru executia efectivă a job-urilor.

Nu o să intru aici în detalii legate de Quartz.Net, cum scopul nu e să scriu un tutorial – din fericire există un tutorial foarte bun deja facut: http://quartznet.sourceforge.net/tutorial/index.html

Cum totuși e o componenta externă, nu ar strica să fie usor de mock-uit la nevoie in unit teste – să vedem dacă oferă interfețe pentru principalele clase..
ISchedulerFactory, IScheduler, IJob – fain.

Ce aș mai verifica înainte de a mă declara satisfăcut de componentă: cateva teste de load și performance, câteva teste pentru partea de error handling (ex.: ce se întamplă când un job aruncă o excepție, când crapă procesul host, când se umple thread pool-ul etc.). Nu în ultimul rând, aș arunca o privire peste codul sursă să vad cât de îngrijit e scris.

Disclaimer: nu știu dacă e cea mai bună componentă pentru așa ceva – probabil sunt altele mai bune. Ideea era să arat cam care ar fi pașii care îi urmez cand aleg o componentă gratis sau open source. Când e vorba de un proiect comercial pe bune, povestea se schimbă într-o oarecare masură: ce buget se poate aloca pentru componente thrid-party, customer support, licensing, company policies (în multe firme se incearcă standardizarea componentelor folosite, nu fiecare proiect să foloseasca ceva diferit) etc.

Posted in .NET, General | Tagged , , , , | 3 comentarii

Vârful Brocken iarna (munții Harz)

HarzBrocken_TudorT_027.jpgHarzBrocken_TudorT_001.jpgHarzBrocken_TudorT_002.jpgHarzBrocken_TudorT_003.jpgHarzBrocken_TudorT_004.jpgHarzBrocken_TudorT_005.jpg
HarzBrocken_TudorT_006.jpgHarzBrocken_TudorT_007.jpgHarzBrocken_TudorT_008.jpgHarzBrocken_TudorT_009.jpgHarzBrocken_TudorT_010.jpgHarzBrocken_TudorT_011.jpg
HarzBrocken_TudorT_012.jpgHarzBrocken_TudorT_013.jpgHarzBrocken_TudorT_014.jpgHarzBrocken_TudorT_015.jpgHarzBrocken_TudorT_016.jpgHarzBrocken_TudorT_017.jpg
HarzBrocken_TudorT_018.jpgHarzBrocken_TudorT_019.jpgHarzBrocken_TudorT_020.jpgHarzBrocken_TudorT_021.jpgHarzBrocken_TudorT_022.jpgHarzBrocken_TudorT_023.jpg

Brocken in winter, a set on Flickr.

Puțini turiști din România știu de acești mici munți din Germania, mult mai batrâni decât Alpii, ce se înalță brusc la marginea nesfarșitei câmpii din nordul Europei.
Pe acest vârf in Faust-ul lui Goethe se adunau vrajitoarele, și tot acolo se mai pot vedea ultimele rămășițe ale “Hercynia Silva”, marea padure ce acoperea în antichitate Germania pe timpul lui Cezar.

Posted in Uncategorized | 2 comentarii

WCF – self-hosting in a Windows Service

Încercând azi sa creez un Windows Service care expune un serviciu WCF m-am lovit de următoarea eroare la serviceHost.Open():

Service cannot be started. System.ServiceModel.AddressAccessDeniedException: HTTP could not register URL http://+:8008/MyServiceName/. Your process does not have access rights to this namespace … System.Net.HttpListenerException: Access is denied

Problema e comună și binecunoscută celor ce lucrează frecvent cu WCF self-hosted, dar..

Cum încercam să rulez Windows Service-ul sub un cont de Network Service, care nu e admin, Windows-ul spune ceva de genul: “nu ai drepturi destule să rezervi acel namespace”.
Soluția (pe Vista, Win7 si Win2008) e relativ simplă: logat ca adminstrator (cmd / Run as Admin..), invocăm formula magică:

C:\windows\system32>netsh http add urlacl url=http://+:8008/MyServiceName/ user="NT AUTHORITY\NETWORKSERVICE"

fără spațiu in NETWORKSERVICE (cu spațiu pare-se nu merge pe sisteme care nu au English locale). Normal, o comandă de genul ăsta ar trebui inclusă cumva într-un installer, care de obicei e rulat de un admin.

Mai multe detalii la: http://msdn.microsoft.com/en-us/library/ms733768.aspx
și mai in detaliu, inclusiv o metodă de a face asta din cod (ugly code): http://msdn.microsoft.com/en-us/magazine/cc163531.aspx

Morala: să nu hostez servicii WCF altfel decât in IIS, decât daca e musai.. :)

Posted in .NET, WCF, WCF | Tagged , , | 4 comentarii

Windows Phone Push Notifications – câteva limite

Nu am de gând sa povestesc ce sunt și cum se folosesc Push Notifications pe Windows Phone. O descriere foarte bună se găsește la http://msdn.microsoft.com/en-us/library/ff402558(v=vs.92).aspx

High-level, e similar cu Apple Push Notifications Service.
A nu se confunda cu Windows Push Notifications din Windows 8, foarte similar dar totuși diferit, măcar la suprafață.

Mai degrabă aș vrea să enumăr o listă de limite de care ar trebui să țină seama cineva care dezvoltă o aplicație ce folosește Push Notification, limite care sunt un pic ascunse prin documentație:

  • se pot crea maxim 30 de push notification chanells per device (era 15 initial) ==> aplicatia trebuie să trateze un posibil InvalidOperationException(PushNotificationChannelQuotaExceeded) când crează un chanell, dacă are ghinionul sa fie deja 30 de chanells create.
  • maxim 1 chanell per aplication/device
  • un service ce trimite push notifications către telefoane, dacă nu e autentificat prin TLS, are o limită de 500 de notificari per subscription (aplicatie/mobil) pe zi (http://msdn.microsoft.com/en-us/library/ff941099(v=VS.92).aspx)
    Când se atinge limita, se primește un cod de eroare (HTTP) 406 (Not Acceptable), cu NotificationStatus=Dropped.
    Pentru o aplicație contra cost, un certificat TLS nu costă asa mult.
  • dimensiunea maximă a unei notificări: 1KB header-ul, 3KB payload-ul
  • (cumva de așteptat) se pare ca se poate folosi doar push notification services oferit de Microsoft, hostat pe Azure (nu unul custom)
  • textul și titlul din toast message și tile updates trebuie să fie scurte, altfel sunt trunchiate (la http://msdn.microsoft.com/en-us/library/ff402558(v=vs.92).aspx sunt limitele mai exacte)
  • imaginile downloadate la tile push notification: max. 173×173, max 80KB, trebuie să se downloadeze in max. 30s, no https
  • Pentru ca aplicația să fie acceptată pe marketplace, trebuie să ceară permisiunea userului să folosească push notifications, deci trebuie să fie opt-in/opțional ==> nu ne putem baza pe push notifications pentru “core”-ul aplicației.
  • Dacă mobilul se conectează la net printr-un WiFi ce trece pritr-un proxy sau firewall, s-ar putea să nu reusească să deschidă un chanell spre Microsoft Push Notification Services

Astea sunt doar limitările la ora actuală pe care le-am descoperit până acuma, nu înseamnă că nu mai sunt și altele.
Și serviciul similar de la Apple are limitările lui, deci nu e ceva neobișnuit (ex.: un mesaj poate avea max. 256bytes).  Serviciul de la Google/Android (C2DM) e puțin mai generos: 1024bytes.

Morala: toată aplicatia trebuie codată defensiv, fără a prespune că notificările vor fi trimise, excepțiile și error code-urile trebuie prinse și tratate, retries și tot tacâmul.. :)

Posted in .NET, Windows Phone | Tagged , , | Lasă un comentariu

Windows Phone – episodul 2

Într-un post precedent, ziceam că voi reveni după câteva săptămâni de folosire a telefonului (WP7 cu Mango pe un HTC7Pro).

O listă cu aplicațiile care le folosesc mai des (deocamdată):

  • evident, email (unificat, GMail + Outlook), IE9
  • People hub (Facebook, Twitter, LinkedIn updates)
  • Bing visual search (deocamdată mai mult pentru barcodes și scan+OCR+translate)
  • The Weather Channel
  • calendar (synch cu Exchange)
  • Nokia Maps si Nokia Drive (beta, side-loaded “ne-oficial”)
  • music (Zune)
  • GReadr (RSS reader)
  • WiFi on/off shorcut
  • DB Navigator
  • Google search app
  • AppFlow (Marketplace UI done right)
  • Screen Capturer

Alte aplicatii instalate care le folosesc mai rar:

  • Yahoo Messenger client (varianta free, cam instabilă si buggy)
  • Tango (voice&video chat)
  • Adobe Reader
  • Amazon Kindle (rar, cum am și un Kindle adevărat)
  • Compass VO
  • Eye On Earth :)
  • FlashLight
  • Folders (greoi de folosit)
  • gMaps (client Google Maps, cam buggy)
  • Last.fm
  • Level
  • Lists
  • Maps (clientul built-in de Bing Maps, ok, dar slab fata de Nokia Drive)
  • Office
  • HTC Stocks (nice, da’ nu am actiuni la bursa)
  • You Tube
  • Sudoku
  • Logic Games

Toate aplicațiile sunt din cele gratis, cum lui Windows Phone Marketplace dintr-un motiv știut doar de Microsoft, nu îi plac cardurile de debit emise în România (chiar dacă vede că ma conectez de pe un IP din Germania și chiar dacă încerc să îl păcălesc alegând altă țară la contul din Windows Live).

În sfârșit, HTC a dat drumul la driverele care permit tethering (internet sharing) și pentru HTC7Pro (verificat și merge pe O2 DE). E limitat la vreo 5 devices simultan, dar e ok cum nu vreau sa fac rețea de cartier conectată prin Windows Phone :) .

Ce îmi lipsește:

  • Skype
  • Lync client (da, ambele de la MS, și nici unul nu are incă un client pe WP7 released)
  • YM client făcut cum trebuie
  • romanian spellchecker (și nici nu se poate adăuga un dicționar custom)
  • custom physical keyboard mapping/layout
  • buton mai mare pentru access la phone dialer pad (când mă grăbesc și trebuie să sun un număr care nu îl am în address book sau history, butonul e la fel de mic ca restul de 3 din app bar).
    Față de un mobil clasic, procesul de formare a unui număr e mai lent:
    push power buton, swipe to unlock, tap Phone app, tap small dial icon, formează numarul.
    La un mobil clasic: push two buttons to unlock, formează numărul.
  • posibilitatea de a schimba search engine-ul default în browser
  • posibilitatea de a defini alt tile background color, custom (și asta fără hacks dificile precum interop unlocking)
  • să pot pune un SD mai mare de 8GB fără a desface telefonul și fără sa desfac 7 șuruburi pierzând garanția cu ocazia asta..
    Înțeleg de ce SD-card-ul nu e ușor accesibil user-ului obișnuit in WP7 (dacă îl schimbă și-a cam pierdut toate aplicațiile), dar puteau să îl pună ușor mai accesibil ). Oricum, partea bună e că se poate schimba (cu unul de 32 GB, doar SanDisk si doar class 2 pare-se) cu puțină răbdare, șurubelnițe potrivite și mâini fine :)  )
  • un docking interface standardizat precum cea de la iPhone (când ajung acasă să pot conecta ușor telefonul la un sistem audio și să se și incarce în timpul ala..)

Ca developer, restricțiile sunt multe, mai ales pentru cine nu are access “oficial” la interop și lumea unmanaged, dar era cumva de așteptat dat fiind modelul “walled garden” similar Apple.

Per ansamblu sunt totuși mulțumit de Windows Phone, mai ales că înbunătățirile continuă să vină.

To be continued..

Posted in Windows Phone | Tagged , , , | Un comentariu

Windows Phone, HTML și fonturi..

Am încercat ieri să imi dau seama dacă e o coincidență sau nu faptul că majoritatea site-urilor care nu au fost gândite special pentru un mobile, pe Windows Phone in IE9, apar cu un font extrem de mic.Inițial m-am gândit că acele site-uri sunt prost gândite și specifică dimensiuni absolute în pixeli (gen 10px), și asta e cauza.
Ca să testez ipoteza, am creat o pagina foarte simplă, doar text, fără nici o dimensiune de font specificată:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Test HTML Page</title>
</head>
<body>
<h1>Header 1</h1>
<h2>Header 2</h2>
<h3>Header 3</h3>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse molestie placerat lacus in ullamcorper. Donec pretium tempor dui, iaculis porttitor nisl faucibus id. ...
</p>
...
În ciuda așteptărilor, pe Windows Phone (Mango, 7.1), în IE 9, implicit pagina rămâne accesibila doar celor cu ochi de vultur sau cu telefoane cu ecrane de 6inchi:

WP7 IE9 Default font size

Portrait sau landscape, arată la fel; un double-tap nu schimbă nimic. Doar zoom-ul mai poate fi folosit pentru a face textul “citibil”.

După mai multe săpături, se pare că nu e un bug, ci “by design”: IE9 pe Windows Phone plecă de la ipoteza că un site care nu a fost optimizat pentru un mobile, nu va arăta ok pe un ecran de 800×480 si 3,6″ diagonala, ceea ce e adevarat în multe cazuri: chiar dacă nu s-au specificat dimensiuni absolute pentru font in px, pagina conține alte elemente (div-uri, imagini, meniuri etc.) care nu știu să își facă reflow automat cand viewport-ul devine foarte mic, ca pe un mobil.

Soluția? Un meta tag care îi zice lui IE: lasă-mi pagina în pace, nu o scala:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Test HTML Page</title>
<meta name="viewport" content="width=device-width" />
</head>
<body>
<h1>Header 1</h1>
<h2>Header 2</h2>
<h3>Header 3</h3>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse molestie placerat lacus in ullamcorper. Donec pretium tempor dui, iaculis porttitor nisl faucibus id. Aliquam sed turpis augue, in dapibus nibh. ...</p>
...

După această modificare, pagina va arăta normal:

WP7 IE9 normal text size

Imaginile de mai sus sunt screen captures de pe device, nu din emulator (pentru cine mai zice ca WP7 nu are soft de screen capture :)

Explicația mai pe îndelete, la: http://blogs.msdn.com/b/iemobile/archive/2011/01/21/managing-the-browser-viewport-in-windows-phone-7.aspx

Probabil soluția nu e cea mai elegantă – urmează să vad cum apare o astfel de pagină pe alte device-uri (iPhone, Android, Opera Mini/Mobile pe Symbian cel putin..).
(dacă vreun posesor de iPhone nimerește din întâmplare pe aici, l-aș ruga să-mi spună cum apare implicit pagina: http://www.turcu.name/playground/mobile.html - fără zoom).

L.E.: Săpând putin mai mult, se pare că <meta name=”viewport” content=”width=device-width” />
e deja un “de facto standard” suportat (mai mult sau mai puțin uniform) pe majoritatea browserelor actuale de pe smartphones cel puțin:

IE pe WP7: http://blogs.msdn.com/b/iemobile/archive/2010/11/22/the-ie-mobile-viewport-on-windows-phone-7.aspx
Firefox mobile (Fenec): https://developer.mozilla.org/en/Mobile/Viewport_meta_tag 
Apple Safari:
http://developer.apple.com/library/safari/#documentation/appleapplications/reference/SafariHTMLRef/Articles/MetaTags.html
Opera Mobile: http://dev.opera.com/articles/view/an-introduction-to-meta-viewport-and-viewport/

Oricum, morala ar fi: pentru pagini simple, care prezintă mai mult conținut, fară layout-uri complexe, nu e musai o versiune “mobile” separata (sau un CSS separat), și cu atât mai mult nu e nevoie de “apps” special făcute pentru fiecare platforma în parte, care doar afișează niște content. În ziua de azi e posibil deoarece foarte putina lume mai foloseste mobile care nu stiu HTML (ci doar WAP), mai toate mobilele suporta macar XHTML 1.0 daca nu HTML5.

Din păcate (sau fericire), idealul unei platforme comune pe web bazată (în ordine cronologica) pe Java Applets, Flash sau Silverlight - in brower (ca plugins) – s-a destrămat de ceva vreme (atât Adobe cât și Microsoft au declarat oficial ca nu vor mai continua să dezvolte sau suporte plugins de Flash sau Silverlight care să ruleze pe mobile, în browsere).

Posted in Windows Phone | Tagged , , , | Lasă un comentariu

O poveste cu doi gemeni în C#

M-am lovit de curând de o situație mai ciudată: două assembly-uri diferite, fără legătură directă între ele, definesc ambele aceeași clasă, în același namespace (nu mă întrebați cum s-a ajuns la situația asta, normal că nu e recomandat etc..).
Problema era: cum folosim ambele clase dintr-un al treilea assembly, in C#? :)

Dacă încercăm, obținem ceva de genul:
[Two identical classes in 2 assemblies 1]

Soluția? “extern alias” și “reference alias” (http://msdn.microsoft.com/en-us/library/ms173212.aspx):

Extern alias

 
Altfel spus, când referențiem assembly-ul, putem defini si un ‘alias’ care definește un “root level namespace”, în paralel cu “global”.
Chestia asta, introdusă prin .NET 2.0 parcă, a fost gândită probabil să rezolve micile “DLL hells” care mai apar și în .NET.. :)

Pentru cei care mai lucreză și cu C++, nu are nici o legătură cu ‘extern’-ul de acolo, care e folosit de ex. pentru a declara o variabilă globală, având “static storage duration and external linkage” (http://en.cppreference.com/w/cpp/language/storage_duration).

De asemenea, ‘extern’ mai e folosit în C#, pentru a declara ca o metodă e definită extern, de ex. in cod nativ intr-un DLL (cu DllImport) – de asemenea nu are legatură cu cazul de mai sus.

Posted in .NET | Tagged , , , | Lasă un comentariu