Fasil Hayat's blog

...C#, .Net, Sharepoint, BizTalk, JQuery...

En meget vigtig ting at bemærke ved XSLT boolean værdier er, håndtering af dem skal foretages på følgende måde:

   1:  <xsl:choose>
   2:      <xsl:when test="boolean(MinBooleanVaerdi)">
   3:          <!-- 'true' -->
   4:      </xsl:when>
   5:      <xsl:otherwise>
   6:          <!-- 'false' -->
   7:      </xsl:otherwise>
   8:  </xsl:choose>


Det er den sikreste måde at teste boolean værdier på, da man under forskellige platforme kan komme ud for, at boolean værdier er repræsenteret som 1 eller 0 istedet for true eller false.



Denne feature kan benyttes, hvis man har behov for at udvide funktionalitet på eksisterende metoder. Man kan fx. have metoder med samme navn og signatur, men med forskellige returtyper. Overload af metoder virker kun, hvis signaturen divergerer. I tilfælde af man skal returnere et forretningsobjekt eller xml serialiseret format af objektet, kan man gøre brug af Extension methods. For at undgå to versioner af ens metoder fx. HentMitObjekt(int id) og HentMitObjektSerialiseret(int id), kan man gøre brug af følgende generic version af en extension method.

   1:  public static class EntityExtension {
   2:     public static XmlDocument ToXmlDocument<T>(this T entity) where T : IXmlable {
   3:              return SerializeHelper.Serialize(entity);
   4:     }
   5:  }


Denne metode extender XmlDocument, og samtidig er der lavet en afgrænsning i form af IXmlable constraint på metoden. Metoden er valgt at blive placeret i en static klasse ved navn EntityExtension. Alle de forretningsobjekter, der skal serialiseres skal implentere IXmlable interfacet.

   1:  public class MitObjekt: IXmlable {
   2:         public int Id { get; set; }
   3:         public string Navn { get; set; }
   4:  }


Man kan herefter gøre følgende:

   1:  var xmldokument = MinManager.HentMitObjekt().ToXmlDocument();


Eller direkte på objektet:

   1:  var mitObjekt = new MitObjekt();
   2:  ...
   3:  ...
   4:  ...
   5:  mitObjekt.ToXmlDocument();


Extension method sørger for man kan kalde ToXmlDocument på alle entiteter der implementerer IXmlable interfacet.



Jeg har lavet et lille simpelt eksempel, der viser brug af System.Runtime.Caching i .Net 4.0 framework. Eksemplet er lavet, da der kan være behov for caching udenfor ASP.Net applikationer, og undgåelse af brug af HttpRuntime.Cache. Principperne er de samme fra mit tidligere indlæg, dog har jeg introduceret en unik cachenøgle, man skal kalde caching som parameter.

Find eksemplet her.

   1:  /// <summary>
   2:  /// Varetager caching af objekter.
   3:  /// </summary>
   4:  public static class CachingHelper {
   5:      /// <summary>
   6:      /// Henter cached data.
   7:      /// </summary>
   8:      /// <typeparam name="T">Generisk format.</typeparam>
   9:      public static T GetCachedData<T>(string key){
  10:          var cache = MemoryCache.Default;
  11:          return cache[key] != null ? (T) cache[key] : default(T);
  12:      }
  13:      /// <summary>
  14:      /// Cacher data.
  15:      /// </summary>
  16:      /// <typeparam name="T">Generisk format.</typeparam>
  17:      public static T CacheData<T>(T o, string key){
  18:          var cache = MemoryCache.Default;
  19:          cache.Add(key, o, new CacheItemPolicy());
  20:          return o;
  21:      }
  22:      /// <summary>
  23:      /// Fjerner cachen.
  24:      /// </summary>
  25:      public static void ClearCache<T>(string key){
  26:          var cache = MemoryCache.Default;
  27:          if (cache.Contains(key) && (cache[key].GetType() == typeof(T)))
  28:          {
  29:              cache.Remove(key);
  30:          } 
  31:      }
  32:  }


'ClearCache' metoden sikrer at typen af det objekt, man vil fjerne fra cachen er valid ifht. nøglen, man sender med som parameter.
Der bør alligevel sættes en fornuftig CacheItemPolicy, hvor man kan definere, hvor længe cachen skal holde på et objekt.
Det kan fx. defineres på følgende måde, hvor der caches i ét minut:

   1:  /// <summary>
   2:  /// Cache politik, der definerer hvorlænge cachen skal holdes.
   3:  /// </summary>
   4:  private static readonly CacheItemPolicy CachePolitik = new CacheItemPolicy
   5:              {
   6:                  SlidingExpiration = new TimeSpan(0, 0, 1, 0)
   7:              };


   1:  private static List<Type> GetAllTypesFromDll(string dllName) {
   2:      var types = new List<Type>();
   3:      try {
   4:          var assembly = Assembly.LoadFrom(dllName);
   5:          Type[] allTypes = assembly.GetTypes();
   6:          types.AddRange(allTypes.Where(type => type.IsInterface));
   7:      } catch (Exception ex) {
   8:          Console.WriteLine("\n\nFejl - ikke valid dll. " + dllName);
   9:          Console.WriteLine("Exception\n" + ex.Message + "\n" + ex.InnerException);
  10:      }
  11:      return types;
  12:  }

   1:  private static IEnumerable<Service> ExtractPublicMethods(IEnumerable<Type> types) {
   2:      var exposedMethods = new List<Service>();
   3:      foreach (Type t in types) {
   4:          var service = new Service{ 
   5:                  Name = string.Format(t.Name.Remove(0, 1) + "{0}", ".svc"), 
   6:                  Operations = new List<string>() 
   7:          };
   8:          service.Operations = t.GetMethods(BindingFlags.Public | 
   9:              BindingFlags.DeclaredOnly | BindingFlags.Instance).
  10:              Select(a => a.Name).ToList();
  11:          exposedMethods.Add(service);
  12:      }         
  13:      return exposedMethods;
  14:  }

   1:  public class Service {
   2:      public List<string> Operations { get; set; }
   3:      public string Name { get; set; }
   4:  }


En hurtig måde at introducere noget letvægts caching af dataobjekter. Der findes caching frameworks og Enterprise Library's udemærkede 'Caching Application Block' (indbygget i .net framework 4.0), kan benyttes til formålet. Nedenstående er for synliggørelse af en enkelt måde at cache databærende objekter på application scope niveau. Cachen bliver tømt, når en bruger lukker browservinduet eller forlader sitet.

Caching klassen:

   1:  namespace MyBlog.Business.Cache {
   2:      /// <summary>
   3:      /// Varetager caching af objekter.
   4:      /// </summary>
   5:      public static class CachingHelper {
   6:          /// <summary>
   7:          /// Henter cached data.
   8:          /// </summary>
   9:          /// <typeparam name="T">Generisk format.</typeparam>
  10:          public static T GetCachedData<T>() {
  11:              return HttpRuntime.Cache[typeof(T).ToString()] != null ? 
  12:                  (T)HttpRuntime.Cache[typeof(T).ToString()] : default(T);
  13:          }
  14:          /// <summary>
  15:          /// Cacher data.
  16:          /// </summary>
  17:          /// <typeparam name="T">Generisk format.</typeparam>
  18:          public static T CacheData<T>(T o) {
  19:              HttpRuntime.Cache.Insert(typeof(T).ToString(), o);
  20:              return o;
  21:          }
  22:          /// <summary>
  23:          /// Tømmer cachen.
  24:          /// </summary>
  25:          public static void ClearCache<T>() {
  26:              HttpRuntime.Cache[typeof(T).ToString()] = null;
  27:          }
  28:      }
  29:  }


Caching hjælperklassen kan herefter bruges på følgende måde:

   1:  /// <summary>
   2:  /// Gets the articles.
   3:  /// </summary>
   4:  public static List<Article> GetArticles() {
   5:     return CachingHelper.GetCachedData<List<Article>>() ??
   6:     CachingHelper.CacheData(DataProviderFactory.GetArticles());
   7:  }


NB!
Eksemplet er i dette udseende en smule farligt, da det forudsætter at List<Article> altid kun findes i een instans, og ikke er sat med andet indhold i en anden kontekst. Eksemplet skal nærmere inspirere fremfor at betragtes som et fuldstændigt eksempel. Nøglen kan derfor ændres til noget andet end 'typeof(T).ToString()', så man ikke kommer i kampolage med det cachede objekt. Nøglen kan være en del af parameteren i cachinghelper kaldene.



SOAP beskeder består af et 'MessageBody' og et 'MessageHeader' segment, hvor man typisk i 'MessageBody' segmentet udveksler forretningsdata, kan man benytte sig af SOAP header til udveksling af sekundære data. Det kan være data, der altid skal sendes med over via SOAP headeren fx. den kaldende parts autorisations data.

Her er et simpelt eksempel på, hvordan man kan berige data udvekslingen med en SOAP header fra en klient, som bagefter kan udvindes hos service udbyderen.

Kontrakter:

   1:  namespace MitNamespace.Foo {
   2:      public class MinMessageHeader{
   3:          public string BrugerId { get; set; }
   4:          public string ApplikationId { get; set; }
   5:      }
   6:  }
   7:   
   8:  namespace MitNamespace.Foo {
   9:      public class HentEtEllerAndetRequest {
  10:          public MessageHeader<MinMessageHeader> Header { get; set; }
  11:          public string EnForretningsId { get; set; }
  12:      }
  13:  }


Klient kode:

   1:  var klient = new MinProxy.MinServiceClient();
   2:   
   3:  using (var scope = new OperationContextScope(klient.InnerChannel)) {
   4:      var req = new HentEtEllerAndetRequest();
   5:      req.EnforretningsId = "25";
   6:      req.Header = new MessageHeader<MinMessageHeader>(new MinMessageHeader {
   7:                      BrugerId = "FHA", 
   8:                      ApplikationId = "NavnPaaApplikation", 
   9:                  });
  10:      var messageHeader = req.Header;
  11:      var header = messageHeader.GetUntypedHeader("MinCustomHeader", 
  12:                                          "http://www.fasil.dk/Applikation");
  13:      OperationContext.Current.OutgoingMessageHeaders.Add(header);
  14:      var result = klient.HentNogleData(req);
  15:  }


Serverkode:

   1:  [OperationContract]
   2:  public HentNogleDataResponse HentNogleData(HentEtEllerAndetRequest request) {
   3:      MessageHeaders headers = OperationContext.Current.IncomingMessageHeaders;
   4:      var headerData = headers.GetHeader<MinMessageHeader>("MinCustomHeader", 
   5:                                          "http://www.fasil.dk/Applikation");
   6:      ...
   7:      ...
   8:      ...
   9:  }


Man kan også benytte sig af data kontrakter istedet. Dette eksempel virker dog helt ubeklageligt. 
Klient koden kan naturligvis bestå af en 'abstract' klasse, hvor header oplysningerne sættes. Alle andre service kaldende klasser skal herefter implementere / nedarve fra denne 'abstract' klasse.

På server delen kan man naturligvis tjekke for headerdelen, inden et response sendes tilbage til klienten. Alternativt sendes en autentificerings- / autorisationsfejl tilbage til klienten, hvis header oplysningerne ikke er gyldige.



Fasil Malik Hayat

Developer
.Net, WCF, Sharepoint, MOSS, Biztalk, JQuery.

linkedin facebook twitter plaxo google+ grooveshark boxee
fasil

Education

fasil

Bachelor of Science (Honours)
De Montfort University, Leicester.

Fag: Java, MVC, Information Strategy, ITIL

Microsoft Certified Technology Specialist

Skills

.net vs2010 - C# sharepoint sql server jquery ubuntu java netbeans


  

Sign in