sobota, 14. júla 2007

.NET - spustenie súkromnej metódy rodičovskej triedy pomocou reflexie

Raz som pri unit testoch potreboval spustiť súkromnú metódu rodičovskej triedy pomocou reflexie. Problémom je, že metóda GetMethod triedy System.Type nevráti MethodInfo pre súkromné metódy definované na úrovni rodičovskej triedy. Môj trik spočíva v tom, že MethodInfo je vytvorené pre rodičovskú triedu a Invoke je volané s parametrom kde je odkaz na triedu potomka:


   1:  // Faq inherits from BusinessObject

   2:  Faq faq = new Faq();    

   3:  RunPrivateMethodOnBusinessObject(faq, "CreateInsertCommand")

   4:   

   5:  private object RunPrivateMethodOnBusinessObject(object obj, string methodName)

   6:  {

   7:      MethodInfo method = typeof(BusinessObject).GetMethod(methodName, BindingFlags.Instance | BindingFlags.NonPublic);

   8:      return method.Invoke(obj, null);

   9:  }

C# - podmienený preklad pomocou ConditionalAttribute

Podmienený preklad v C# môžeme zrealizovať pomocou kódu:


   1:  #if DEBUG

   2:  void ConditionalMethod()

   3:  {

   4:      // ....

   5:  }

   6:  #endif


Elegantnejšie riešenie je podľa mňa použitie atribútu [Conditional], pretože pokiaľ nebude definovaný symbol DEBUG, tak aj volania metódy ConditionalMethod budú pri preklade vynechané:


   1:  [Conditional("DEBUG")]

   2:  void ConditionalMethod()

   3:  {

   4:      // ....

   5:  }

WS-Security pomocou WSE 3.0 bez X.509 certifikátov

Nedávno som potreboval zabezpečiť webovú službu aspoň na takej úrovni, aby jej nemohol hocikto posielať správy. Rozhodol som sa použiť Web Services Enhancements 3.0 for Microsoft .NET. Chcel som, aby SOAP správy prichádzajúce k webovej službe boli digitálne podpísané (aby počas prenosu sieťou nikto nemohol meniť obsah správy), nechcel som však použiť X.509 certifikáty pretože by bol problém s ich použitím v prostredí kde mala byť aplikácia nasadená. Riešenie som našiel v článku Custom WSE 3.0 Policy Assertions for Signing and Encrypting SOAP Messages with Username Tokens. V riešení je na digitálny podpis použitý username token.

ASP.NET - DataGrid renderovaný s thead, tbody, th, ....

Štandartne sa DataGrid renderuje tagmi <table>, <tr> a <td>. Pre zjednodušenie štýlovania tabuľky pomocu CSS je vhodné okrem spomínaných tagov renderovať aj tágy <thead>, <tbody>, <th> a podobne. Na riešenie tohto problému som vytvoril vlastný DataGrid odvodený od System.Web.UI.WebControls.DataGrid pričom v prekrytej metóde OnPreRender sú vykonané všetky potrebné úpravy:


   1:  using System;

   2:  using System.Reflection;

   3:  using System.Web.UI;

   4:  using System.Web.UI.WebControls;

   5:   

   6:  namespace NMarian.Controls

   7:  {

   8:      public class DataGrid : System.Web.UI.WebControls.DataGrid

   9:      {

  10:          protected override void OnPreRender(EventArgs e)

  11:          {

  12:              Table table = Controls[0] as Table;

  13:   

  14:              if (table != null && table.Rows.Count > 0)

  15:              {

  16:                  table.Rows[0].TableSection = TableRowSection.TableHeader;

  17:                  table.Rows[table.Rows.Count - 1].TableSection = TableRowSection.TableFooter;

  18:   

  19:                  FieldInfo field = typeof(WebControl).GetField("tagKey", BindingFlags.Instance | BindingFlags.NonPublic);

  20:   

  21:                  foreach (TableCell cell in table.Rows[0].Cells)

  22:                  {

  23:                      field.SetValue(cell, HtmlTextWriterTag.Th);

  24:                  }

  25:              }

  26:   

  27:              base.OnPreRender(e);

  28:          }

  29:      }

  30:  }

ASP.NET - ako zistiť, či už stránka bola validovaná?

V niektorých situáciach potrebujeme zistiť, či už prebehla validácia stránky. Ak by sme zavolali Page.IsValid ešte predtým ako prebehla validácia, tak by sme dostali výnimku. Moje riešenie tohto problému znázornené v nasledujúcej utilite využíva mechanizmus reflexie:


   1:  using System.Web;

   2:  using System.Web.UI;

   3:  using System.Reflection;

   4:   

   5:  public class PageUtil

   6:  {

   7:      public static bool IsPageValidated()

   8:      {

   9:          Page page = HttpContext.Current.Handler as Page;

  10:          if (page == null) throw new HttpException("This method can be called only in classes derived from System.Web.UI.Page");

  11:          FieldInfo fieldValidated = typeof(Page).GetField("_validated", BindingFlags.Instance  BindingFlags.NonPublic);

  12:          return (bool)fieldValidated.GetValue(page);

  13:      }

  14:  }

streda, 11. júla 2007

IL Merge - spájanie viacero .NET assemblies do jednej

Včera som potreboval spojiť viacero .NET assemblies (jedna .exe a viacero .dll) do jednej. Vytvoril som jednoduchú WinForms aplikáciu, ktorá sa mala distribuovať iba kopírovaním (nechcel som použiť inštaláciu ani ClickOnce). Obsahovala jeden .exe súbor, viacero .dll a konfiguračný súbor.

Na spájanie assemblies je určená utilita IL Merge. Pre konfiguračný súbor (app.config) som nastavil build action na embedded resource, čím sa stal súčasťou .exe súboru. Potom som v post-build event spustil IL Merge:

"c:\Program Files\Microsoft\ILMerge\ILMerge.exe"
/out:SingleAssembly.exe MyApp.exe Library1.dll Library2.dll Library3.dll


Výsledkom je jediný súbor SingleAssembly.exe