Fasil Hayat's blog

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

Et uheldigt symptom på noget xmldata, der i en løsning ikke accepterer namespace prefixes, kan det desværre være nødvendigt at fjerne dem. Har man data i følgende format:

   1:  <?xml version="1.0" encoding="utf-8"?>
   2:  <ns0:MineXmlData xmlns:ns0="http://www.google.com/schemas/minedata">
   3:      <ns0:Personer>
   4:          <ns0:Person></ns0:Person>
   5:      </ns0:Personer>
   6:  </ns0:MineXmlData>


Kan man med følgende regexp fjerne 'ns0' prefix fra xml data.

   1:  (?<=<)[a-zA-Z0-9]+:|(?<=/)[a-zA-Z0-9]+:|(?<=xmlns):.+?(?==)


.Net kode:

   1:  /// <summary>
   2:  /// Fjerner namespace prefix fra xml data.
   3:  /// </summary>
   4:  /// <param name="xmlData">xml data.</param>
   5:  /// <returns>Xml data uden namespace prefix.</returns>
   6:  public static XmlDocument FjernNamespacePrefix(string xmlData)
   7:  {
   8:      string pattern = "(?<=<)[a-zA-Z0-9]+:|(?<=/)[a-zA-Z0-9]+:|(?<=xmlns):.+?(?==)";
   9:      var regXml = new Regex(pattern, RegexOptions.Compiled);
  10:      
  11:      var behandletXmlDokument = new XmlDocument();
  12:      behandletXmlDokument.LoadXml(regXml.Replace(xmlData, string.Empty));
  13:      
  14:      return behandletXmlDokument;
  15:  }


Dette er dog ikke særligt velset, da namespaces netop gør xml repræsentationen typestærkt og undgåelse af sammenfald med andre xml data af samme navn. Hvis der er en god grund til at fjerne namespaces, kan ovenstående regexp bruges.



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:              };


Har man behov for at fjerne en låst fil hos en bruger eller et workspace (typisk hvis bruger ikke findes mere eller workspace er blevet slettet), skal følgende kommando køres i en VS cmd prompt:
tf undo /workspace:OtherUserWorkspace;OtherUser $/Project/File.cs /s:http://tfsserver:8080

Skal man slette et workitem:
witadmin destroywi /collection:CollectionURL /id:id [/noprompt]



   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