Fasil Hayat's blog

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

   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.



Der er masser af eksempler på forretningsbegreber og forretningsbetegnelser, der undergår en anden navngivning under fysisk gengivelse i form af entiteter og deres indbyrdes forhold. De forretningsmæssige navne skal / bør altid bibeholdes ved formidling af viden udenom systemerne og som kommunikationsmiddel mellem forretningen og teknikere for at mindske misforståelser og for at fremme forretningskendskabet. Dog er der intet behov for at manifestere redundante elementer af navne ved gengivelse af begreberne i den fysiske klassificering af objekthierakiet. Taksonomien skal med andre ord udnyttes i entiteternes indbyrdes relationer. Konteksten bliver hermed den styrende del for sammensætningen af objekthierakiet, og man undgår redundant gentagelse af navnet.

Et meget banalt eksempel, der tydeligt illustrerer den semantiske tese (uden nedarvning):

   1:  public class Bord {
   2:      public Plade Plade { get; set; }
   3:      public Ben Ben { get; set; }
   4:  }
   5:   
   6:  public class Plade {
   7:      public int Laengde { get; set; }
   8:      public int Bredde { get; set; }
   9:  }
  10:   
  11:  public class Ben {
  12:      public int Laengde { get; set; }
  13:      public int Antal { get; set; }
  14:  }
  15:   
  16:  public class TestBord {
  17:      public Bord HentBord() {
  18:          var bord = new Bord();
  19:   
  20:          bord.Plade = new Plade();
  21:          bord.Plade.Bredde = 50;
  22:          bord.Plade.Laengde = 100;
  23:   
  24:          bord.Ben = new Ben();
  25:          bord.Ben.Laengde = 30;
  26:          bord.Ben.Antal = 4;
  27:   
  28:          return bord;
  29:      }
  30:  }

Ser man på semantikken i eksemplet, vil man se, at klasserne ikke hedder 'Bordplade' eller 'Bordben', da de implicit bliver tydelige, i den kontekst objekterne bliver brugt i (bord.Plade istedet for det redundante bord.BordPlade).

{bord.{Plade}.Bredde} = 50; //Bordplade og Pladebredde

{bord.{Ben}.Laengde} = 30;
//Bordben og Benlaengde

Desuden bliver disse entiteter åbne og generelle og kan derfor bruges i andre entiteter, men kun hvis egenskaberne tillader genbrugen. Fx. kan 'Ben' entiteten indgå som en del af 'Stol' entiteten, da en stol også har ben.

Det vil dog være forkert at bruge 'Ben' entiteten i person eller dyr entiteter, selvom de overordnede egenskaber tillader det (antal, længde m.m), men her vil domænet dog være forkert, da forretningsdomænet her kunne være møbler og ikke organismer.



Efter flere timers kamp med følgende fejl, fandt jeg endelig roden til problemet.

If ref is present, all of <complexType>, <simpleType>, <key>, <keyref>, <unique>, nillable, default, fixed, form, block, and type must be absent.


Umiddelbart kan der være flere muligheder. Hvad fejlbeskrivelsen ret banalt hentyder til, er lige nøjagtigt det, der er problemet. I første omgang lyder det som en ret kryptisk fejl, som jeg ganske enkelt heller aldrig har set før.
I dette tilfælde var det nemlig ulovlig brug af 'Nillable' i en 'ref, der viste sig at være problemet. Dog kunne man ikke helt se hvor fejlen lå, da der var en del nestede schemaer med reference ('ref's).

<xs:element ref="ent:Entitet" nillable="true" minOccurs="0"/>

rettet til:

<xs:element ref="ent:Entitet" minOccurs="0"/>

Et par timers kamp og man er lige pludselig blevet en smule klogere på xml schemaer.



Der kan være situationer, hvor medarbejdere eller konsulenter ikke længere gør brug af deres pc'er. Det ene problem kan være de har glemt at checke deres ting ind, hvilket kan tages hånd om i TFS administrations delen. Det andet problem kan være, at der er bundet et workspace for en specifik bruger på en specifik folder. Er der planer om at en anden skal overtage pc'en eller udviklings image, låser den forrige bruger workspacets lokale folder. Man kan slette denne binding på følgende måde (du skal være TFS administrator):

- Åbn 'Visual Studio Command Prompt (2010)'
- Træk en rapport over antallet af workspaces

'tf workspaces /computer:[COMPUTERNAVN] /owner:* /format:detailed'

Dette vil give et overblik over antallet af brugere med de låste workspace foldere.

Slet workspace på følgende måde:

- 'tf workspace /delete [COMPUTERNAVN];[BRUGERINITIALER] /server:http://[TFSURL]'

Der vil komme en advarsel om, at man ikke vil kunne genskabe workspace bindingen igen, og en angivelse af hvor mange 'Pending changes' brugeren har. Løs pending changes konflikt og kør kommandoen igen.

Nu kan workspaces mappes igen.



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