Fasil Hayat's blog

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

Jeg er ved at forelske mig lidt i Teleriks OpenAccess ORM som OR-mapper. For det første er den gratis, og så er den ret nem at bruge.

[Opdateret]
Telerik har noget af den mest irriterende og aggressive marketing strategi, hvor diverse køb af deres andre produkter popper op ved start af VS2010. Det kan være VS2010 har nogle problemer, men føj hvor er det belastende, at de ikke i det mindste har en checkbox, hvor man kan bede om ikke at blive notificeret / forstyrret yderligere. Telerik er hermed røget ned i bunden af mig efter efterfølgende brug.
Jeg vil nu hellere bruge Entity Framework 5. Telerik er streget væk fra min liste af brugbare tools. VÆK!

http://tv.telerik.com/products/orm



Til dynamisk indlæsning af konfigurationer, der er applikationsspecifikke, kan nedestående kode benyttes til at tilgå konfiguration for den enkelte applikation.
Et applikationskontekst bliver etableret og herigennem kan konfigurationsværdier tilgås. I dette tilfælde er almindelige konfigurationsværdier, sti for log4net og windsor konfiguration placeret i en enkel konfigurationsfil i en applikationsspecifik mappe.

Navnet på applikationen og mappen er en-til-en og indlæsning sker een gang for alle, og herefter kan singleton klassen tilgås på tværs af assemblies i den samme applikation.

   1:   /// <summary>
   2:   /// Applikationskontekst for applikationen.
   3:   /// </summary>
   4:   public sealed class ApplikationKontekst : Kontekst
   5:   {
   6:       /// <summary>
   7:       /// Lås på instans.
   8:       /// </summary>
   9:       private static readonly object SyncRoot = new object();
  10:   
  11:       /// <summary>
  12:       /// Instans af applikationskontekst.
  13:       /// </summary>
  14:       private static volatile ApplikationKontekst instans;
  15:   
  16:       /// <summary>
  17:       /// Instans af applikationskontekst.
  18:       /// </summary>
  19:       public static ApplikationKontekst Instans
  20:       {
  21:           get
  22:           {
  23:               lock (SyncRoot)
  24:               {
  25:                   return instans ?? (instans = new ApplikationKontekst
  26:                       {
  27:                           Navn = Assembly.GetCallingAssembly().GetName().Name
  28:                       });
  29:               }
  30:           }
  31:       }
  32:   
  33:       /// <summary>
  34:       /// Sætter nyt kontekst objekt op.
  35:       /// </summary>
  36:       public static void SetupKontekst()
  37:       {
  38:           Instans.Navn = Assembly.GetCallingAssembly().GetName().Name;
  39:       }
  40:   }


Kontekst klassen:

   1:   /// <summary>
   2:   /// Kontekst.
   3:   /// </summary>
   4:   public abstract class Kontekst
   5:   {
   6:       /// <summary>
   7:       /// Navn på assembly eller applikation.
   8:       /// </summary>
   9:       public string Navn { get; set; }
  10:   
  11:       /// <summary>
  12:       /// Konfigurationer fra konfigurationsstien.
  13:       /// </summary>
  14:       public Configuration Konfiguration
  15:       {
  16:           get
  17:           {
  18:               return KonfigurationProvider.HentKonfiguration(
  19:                   Konfigurationer.Default[FriendlyNavn(this.Navn)].ToString());
  20:           }
  21:       }
  22:   
  23:       /// <summary>
  24:       /// Fjerner evt. det fuld kvalificerede (Fully Qualified name)
  25:       ///  navn på assembly. Dvs. fjerner evt. namespaces.
  26:       /// </summary>
  27:       /// <param name="applikation">Navn på assembly.</param>
  28:       /// <returns>Det korte navn på assembly uden fuld namespace.</returns>
  29:       private static string FriendlyNavn(string applikation)
  30:       {
  31:           // Regexp udtryk søger bagfra i strengen, og fjerner alt fra '.'
  32:           // og nedefter. (dvs. fra højre mod venstre).
  33:           var regex = new Regex(@"(?<=\.)[^.]*$|^[^.]*$");
  34:           return regex.Match(applikation).Value;
  35:        }
  36:   }


Til indlæsning af konfigurationsfil:

   1:  public static class KonfigurationProvider
   2:  {
   3:      /// <summary>
   4:      /// Konfiguration objekt.
   5:      /// </summary>
   6:      private static Configuration konfiguration;
   7:   
   8:      /// <summary>
   9:      /// Henter konfiguration.
  10:      /// </summary>
  11:      /// <param name="konfigurationsfilSti"> The konfigurations Path. </param>
  12:      /// <returns> Konfigrationsobjekt i applikaitonshukommelse. </returns>
  13:      public static Configuration HentKonfiguration(string konfigurationsfilSti)
  14:      {
  15:          if (konfiguration != null)
  16:          {
  17:              return konfiguration;
  18:          }
  19:   
  20:          var filmap = new ExeConfigurationFileMap
  21:              {
  22:                  ExeConfigFilename = konfigurationsfilSti
  23:              };
  24:   
  25:          konfiguration = ConfigurationManager.OpenMappedExeConfiguration(
  26:              filmap, ConfigurationUserLevel.None);
  27:   
  28:          return konfiguration;
  29:      }
  30:  }


Værdierne tilgås herefter:

var a = ApplikationKontekst.Instans.Konfiguration.AppSettings.Settings["Windsor"].Value;
var b = ApplikationKontekst.Instans.Konfiguration.AppSettings.Settings["Log4Net"].Value;

Jeg er blevet spurtgt af flere, hvorfor der er behov for alt dette. Det korte svar er, at det kan være et alternativ til SSO i BizTalk.
Dog skal man være opmærksom, at denne måde at indlæse kræver at mappen, der holder på konfigurationerne ligger udenfor applikationen, hvilket ikke er oplagt i clustered miljøer.



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


Først skal IIS'en, der hoster Sharepoint 2010 sitet konfigureres for at WCF Services kommer til at fungere.

- Åbn IIS'en
- Find Sharepoint sitet og gå ind under 'Authentication'
- Sæt 'Anonymous Authentication' til disabled
- Sæt 'Basic Authentication' til enabled (hvis man sidder på en udviklerboks. Skal ellers være disabled).

Herefter laver man en Service reference til fx. 'http://MinBoks/sites/MitSite/_vti_bin/ListData.svc' i VS2010.
Man vil herefter få adgang til 'MitSiteDataContext', som skal benyttes for at få adgang til alle SP lister, der findes under 'MitSite'.

Man kan gøre brug af LINQ for at tilgå sharepoint 2010 lister på 'MitSite'. Inden da skal kontekst objekt sættes op. og Credentials skal sættes op. Bemærk kun credentials til en bruger, der har læse rettigheder til en SP 2010 liste, kan afvikle nedenstående kode.

   1:  var host = new Uri("http://MinBoks/sites/MitSite");
   2:  var kontekst = new MitSiteDataContext(new Uri
   3:              (string.Format("{0}/_vti_bin/ListData.svc", host)));
   4:  kontekst.Credentials = CredentialCache.DefaultCredentials;


LINQ udtryk der henter alle SPListItems fra 'MinSPListe' og danner en List<Artikel>:

   1:  var artikler = kontekst.MinSPListe.Where(
   2:                  p => p.Name == "John Doe").Select(p => new Artikel()
   3:                  {
   4:                      Title = p.Title,
   5:                      Id = p.Id,
   6:                      Kode = p.kode
   7:                  }).ToList();


Ved indhentning af et specifikt SPListItem:

   1:  var artikel = kontekst.MinSPListe.Where(
   2:                  p => p.Id == 5).Select(p => new Artikel()
   3:                  {
   4:                      Title = p.Title,
   5:                      Id = p.Id,
   6:                      Kode = p.kode,
   7:                      Name = p.Name,
   8:                      Path = p.Path
   9:                  }).FirstOrDefault();

 



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]



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