Rohit Gupta

Engaging talk on Microsoft Technologies ....My Resume

  Home  |   Contact  |   Syndication    |   Login
  43 Posts | 0 Stories | 52 Comments | 0 Trackbacks

News



Twitter












Archives

Image Galleries

Personal

Saturday, March 30, 2013 #

For this we need to setup a AppFabric Cluster on-premise…. or setup a Caching Worker role (or colocated Caching) on Azure.

The steps for the same are mentioned in this blog post:

Configure MVC app to use onpremise AppFabric Cache or use Azure Caching.

So once we have AppFabric Cache setup. to use this AppFabric Cache as the second level Cache in NHibernate is very simple:

We need to add a nuget package as shown below (NHibernate second-level cache provider):

image

One this has been added, this automatically adds the following configuration to web.config:

   1: <configSections>
   2:   <section name="dataCacheClients" type="Microsoft.ApplicationServer.Caching.DataCacheClientsSection, Microsoft.ApplicationServer.Caching.Core" allowLocation="true" allowDefinition="Everywhere" />
   3:   <section name="AppFabricProviderSettings" type="NHibernate.Caches.AppFabric.AppFabricProviderSettings, NHibernate.Caches.AppFabric" />
   4: </configSections>
   5:  
   6: <AppFabricProviderSettings CacheType="Named" NamedCacheTypeRegionName="nhibernate" NamedCachesMustExist="false" LockTimeout="30000" LocksRegionName="Locks" />

For more information get the details from this blog (or search the following term in google: “NHibernate second level cache with AppFabric “ ):

https://github.com/SimonTaylor/NHibernate.Caches.AppFabric

http://www.sharpcoder.co.uk/post/2012/01/04/NHibernateCachesAppFabric.aspx

http://www.sharpcoder.co.uk/post/2012/01/11/NHibernateCachesAppFabric-Documentation.aspx

Now in the NHibernate configuration we need to enable second level cache and use NHibernate.Caches.AppFabric as the second level cache.

Here is the code that does the same:

   1: var cacheToUse = ConfigurationManager.AppSettings["cacheToUse"] ?? "InMemoryCache";
   2: var cfg = Fluently.Configure()
   3:     .Database(MsSqlConfiguration.MsSql2008.ConnectionString(connectionString)
   4:                   .Provider("NHibernate.Connection.DriverConnectionProvider, NHibernate")
   5:                   .Dialect<CustomMsSql2008Dialect>()
   6:                   .Driver<SqlAzureClientDriver>()
   7:                   .ShowSql())
   8:     .Cache(x =>
   9:                {
  10:                    if (cacheToUse == "InMemoryCache")
  11:                        x.UseSecondLevelCache().ProviderClass<HashtableCacheProvider>().UseMinimalPuts();
  12:                    else
  13:                        x.UseSecondLevelCache().ProviderClass<NHibernate.Caches.AppFabric.AppFabricProvider>().UseMinimalPuts();
  14:                })
  15:     .CurrentSessionContext("NHibernate.Context.ThreadStaticSessionContext, NHibernate")
  16:     .Mappings(m =>
  17:     {
  18:         m.FluentMappings.Conventions.Setup(x => x.Add(AutoImport.Never()));
  19:         m.FluentMappings.Conventions.AddFromAssemblyOf<ClassConvention>();
  20:         foreach (var assembly in assemblies)
  21:         {
  22:             m.FluentMappings.AddFromAssembly(assembly);
  23:         }
  24:     })
  25:     .ExposeConfiguration(c =>
  26:                              {
  27:                                  c.SetProperty(Environment.TransactionStrategy, typeof(ReliableAdoNetWithDistributedTransactionFactory).AssemblyQualifiedName);
  28:                                  NHibernateCfg = c;
  29:                                  c.LinqToHqlGeneratorsRegistry<ExtendedLinqtoHqlGeneratorsRegistry>();
  30:                              })
  31:     .BuildConfiguration();

Here are the steps:

I am using Windows Azure Caching preview on the cloud for caching purposes on Azure, which can be colocated Cache or a dedicated Cache Worker Role.

Note we have not used the Azure AppFabric cache which is available as a separate service from Azure and comes at a high cost.

I have an appSetting key that will be used to distinguish whether I will be using AppFabric Cache or System.Runtime.Caching.MemoryCache for my caching needs.

   1: var cacheToUse = ConfigurationManager.AppSettings["cacheToUse"] ?? "InMemoryCache";
   2: if (RoleEnvironment.IsAvailable || cacheToUse == "AppFabricCache")
   3: {
   4:     container.RegisterInstance(typeof(ObjectCache), new AppFabricCacheProvider(), new ContainerControlledLifetimeManager());
   5: }
   6: else
   7: {
   8:     container.RegisterInstance(typeof(ObjectCache), MemoryCache.Default, new ContainerControlledLifetimeManager());
   9: }

In the above code snippet… I am registering AppFabricCacheProvider as my Cache provider… if my appSetting states that I need to use On-Premise AppFabric Cache or the Azure Caching preview.

The code for AppFabricCacheProvider is listed at the bottom of this post.

Caching and MVC application on-premise

If we need to use the on-premise AppFabric Cache (when we are deploying the mvc app to self hosted datacenter or on-premise), here are the steps for setting up on-premise Cache.

First  in the MVC application, we need to add a nuget package (Server AppFabric Client) as show below:

image

On the Server where we will deploy this app, we need to install AppFabric Caching service.

Install the latest version of AppFabric which is AppFabric 1.1.

You can get AppFabric 1.1 from here:

http://www.microsoft.com/en-in/download/details.aspx?id=27115

If you are upgrading from AppFabric 1.0, please follow these steps to upgrade your AppFabric Caching service to 1.1:

http://msdn.microsoft.com/en-us/library/hh343304(v=azure.10).aspx

Please insure that your AppFabric server lists the following when you query it using powershell:

PS C:\Windows\system32> Get-CacheHost

HostName : CachePort   Service Name            Service Status Version Info
--------------------   ------------            -------------- ------------
ISQA.asl.mum.sst:22233 AppFabricCachingService UP             3 [3,3][1,3]

=====================

We also need to set permissions on the cache-cluster so that the MVC app can connect to it.

If we need to grant specific permissions, then we need to use the following powershell command to grant permissions to the ApplicationPoolIdentity account:

PS C:\Windows\system32> Grant-CacheAllowedClientAccount

cmdlet Grant-CacheAllowedClientAccount at command pipeline position 1
Supply values for the following parameters:
Account: "IIS AppPool\DefaultAppPool"

=======================================================

As an alternative we can configure the AppFabric Cache cluster to not look for permissions:

use the following command:

PS C:\Windows\system32> Set-CacheClusterSecurity

cmdlet Set-CacheClusterSecurity at command pipeline position 1
Supply values for the following parameters:
SecurityMode: None
ProtectionLevel: None

===============================================================

On the client (mvc app side) use the following in web.config:

   1: <dataCacheClients>
   2:   <dataCacheClient name="default">
   3:     <hosts>
   4:       <host name="localhost" cachePort="22233"/>
   5:     </hosts>
   6:     <securityProperties mode="None" protectionLevel="None" />
   7:   </dataCacheClient>
   8: </dataCacheClients>

After the Cache service has been up and running. we just need the right configuration in the web.config to be able to connect to it:

===================================================================================================================
   1: <configSections>
   2:   <section name="dataCacheClients" type="Microsoft.ApplicationServer.Caching.DataCacheClientsSection, Microsoft.ApplicationServer.Caching.Core" allowLocation="true" allowDefinition="Everywhere" />
   3:   <section name="AppFabricProviderSettings" type="NHibernate.Caches.AppFabric.AppFabricProviderSettings, NHibernate.Caches.AppFabric" />
   4: </configSections>
   5: <appSettings>
   6:   <add key="cacheToUse" value="AppFabricCache" xdt:Transform="SetAttributes" xdt:Locator="Match(key)"/>
   7: </appSettings>
   8: <dataCacheClients xdt:Transform="Replace">
   9:   <dataCacheClient name="default">
  10:     <hosts>
  11:       <host name="localhost" cachePort="22233"/>
  12:     </hosts>
  13:     <securityProperties mode="None" protectionLevel="None" />
  14:   </dataCacheClient>
  15: </dataCacheClients>

===================================================================================================================

We can configure the session state to use this caching provider.

   1: <sessionState xdt:Transform="Replace" mode="Custom" customProvider="AppFabricCacheSessionStoreProvider">
   2:   <providers>
   3:     <add name="AppFabricCacheSessionStoreProvider" type="Microsoft.Web.DistributedCache.DistributedCacheSessionStateStoreProvider, Microsoft.Web.DistributedCache" cacheName="default" useBlobMode="true" dataCacheClientName="default" applicationName="SCMProfitWeb" />
   4:   </providers>
   5: </sessionState>

We can also configure output cache to use this AppFabric Caching provider:

   1: <caching>
   2:   <outputCache xdt:Transform="Replace" defaultProvider="defaultProvider" >
   3:     <providers>
   4:       <add cacheName="default"
   5:            name="defaultProvider"
   6:            dataCacheClientName="default"
   7:            applicationName="SCMProfitWeb"
   8:            type= "Microsoft.Web.DistributedCache.DistributedCacheOutputCacheProvider, Microsoft.Web.DistributedCache" />
   9:     </providers>
  10:   </outputCache>
  11: </caching>

===================================================================================================================

Caching and MVC application on the cloud

Now the configuration steps for Azure Caching preview is very simple. (Caching and MVC application on the cloud)

There are no provisioning steps for setting up the Cache Cluster on the cloud. we only need to enable Caching preview in the Cloud project, or add a Caching worker role.

Once that is done we need to configure the web.config to use the AppFabric Cache:

   1: <dataCacheClients>
   2:   <dataCacheClient name="default">
   3:     <autoDiscover isEnabled="true" identifier="SCMProfitWeb" />
   4:     <localCache isEnabled="true" sync="TimeoutBased" objectCount="100000" ttlValue="300" />
   5:   </dataCacheClient>
   6: </dataCacheClients>
   7: <AppFabricProviderSettings CacheType="Named" NamedCacheTypeRegionName="nhibernate" NamedCachesMustExist="false" LockTimeout="30000" LocksRegionName="Locks" />

The steps for using Caching Preview as the caching provider for both session state and output cache is the same as shown above for on-premise Cache (isnt that cool…. note this is only possible with AppFabric 1.1)

===================================================================================================================

AppFabric Cache Provider implementation code:

===================================================================================================================

   1: /// <summary>
   2: /// Windows Azure AppFabric Cache implementation of ObjectCache
   3: /// </summary>
   4: public class AppFabricCacheProvider : ObjectCache, IDisposable
   5: {
   6:     private DataCacheFactory _cacheFactory;
   7:  
   8:     private const string RegionKeyTemplate = "{0}:{1}";
   9:  
  10:     /// <summary>
  11:     /// Initializes a new instance of the <see cref="AppFabricCacheProvider"/> class.
  12:     /// </summary>
  13:     public AppFabricCacheProvider()
  14:     {
  15:         _cacheFactory = new DataCacheFactory();
  16:     }
  17:  
  18:     public override string Name
  19:     {
  20:         get { return "AppFabricCacheService"; }
  21:     }
  22:  
  23:     public override DefaultCacheCapabilities DefaultCacheCapabilities
  24:     {
  25:         get { return DefaultCacheCapabilities.OutOfProcessProvider | DefaultCacheCapabilities.AbsoluteExpirations | DefaultCacheCapabilities.SlidingExpirations; }
  26:     }
  27:  
  28:     public override object this[string key]
  29:     {
  30:         get
  31:         {
  32:             return this.Get(key, null);
  33:         }
  34:  
  35:         set
  36:         {
  37:             throw new NotSupportedException();
  38:         }
  39:     }
  40:  
  41:     /// <summary>
  42:     /// When overridden in a derived class, inserts a cache entry into the cache, specifying a key and a value for the cache entry, and information about how the entry will be evicted.
  43:     /// </summary>
  44:     /// <param name="key">A unique identifier for the cache entry.</param>
  45:     /// <param name="value">The object to insert.</param>
  46:     /// <param name="policy">An object that contains eviction details for the cache entry. This object provides more options for eviction than a simple absolute expiration.</param>
  47:     /// <param name="regionName">Optional. A named region in the cache to which the cache entry can be added, if regions are implemented. The default value for the optional parameter is null.</param>
  48:     /// <returns>
  49:     /// If a cache entry with the same key exists, the specified cache entry's value; otherwise, null.
  50:     /// </returns>
  51:     public override object AddOrGetExisting(string key, object value, CacheItemPolicy policy, string regionName = null)
  52:     {
  53:         return this.AddOrGetExisting(new CacheItem(key, value, regionName), policy).Value;
  54:     }
  55:  
  56:     /// <summary>
  57:     /// When overridden in a derived class, inserts a cache entry into the cache, by using a key, an object for the cache entry, an absolute expiration value, and an optional region to add the cache into.
  58:     /// </summary>
  59:     /// <param name="key">A unique identifier for the cache entry.</param>
  60:     /// <param name="value">The object to insert.</param>
  61:     /// <param name="absoluteExpiration">The fixed date and time at which the cache entry will expire.</param>
  62:     /// <param name="regionName">Optional. A named region in the cache to which the cache entry can be added, if regions are implemented. The default value for the optional parameter is null.</param>
  63:     /// <returns>
  64:     /// If a cache entry with the same key exists, the specified cache entry's value; otherwise, null.
  65:     /// </returns>
  66:     public override object AddOrGetExisting(string key, object value, DateTimeOffset absoluteExpiration, string regionName = null)
  67:     {
  68:         return this.AddOrGetExisting(new CacheItem(key, value, regionName), new CacheItemPolicy { AbsoluteExpiration = absoluteExpiration }).Value;
  69:     }
  70:  
  71:     /// <summary>
  72:     /// When overridden in a derived class, inserts the specified <see cref="T:System.Runtime.Caching.CacheItem"/> object into the cache, specifying information about how the entry will be evicted.
  73:     /// </summary>
  74:     /// <param name="value">The object to insert.</param>
  75:     /// <param name="policy">An object that contains eviction details for the cache entry. This object provides more options for eviction than a simple absolute expiration.</param>
  76:     /// <returns>
  77:     /// If a cache entry with the same key exists, the specified cache entry; otherwise, null.
  78:     /// </returns>
  79:     public override CacheItem AddOrGetExisting(CacheItem value, CacheItemPolicy policy)
  80:     {
  81:         var data = this.Get(value.Key, value.RegionName);
  82:         if (data != null)
  83:         {
  84:             return new CacheItem(value.Key, data, value.RegionName);
  85:         }
  86:  
  87:         this.Set(value, policy);
  88:         return value;
  89:     }
  90:  
  91:     /// <summary>
  92:     /// When overridden in a derived class, tries to insert a cache entry into the cache as a <see cref="T:System.Runtime.Caching.CacheItem"/> instance, and adds details about how the entry should be evicted.
  93:     /// </summary>
  94:     /// <param name="item">The object to add.</param>
  95:     /// <param name="policy">An object that contains eviction details for the cache entry. This object provides more options for eviction than a simple absolute expiration.</param>
  96:     /// <returns>
  97:     /// true if insertion succeeded, or false if there is an already an entry in the cache that has the same key as <paramref name="item"/>.
  98:     /// </returns>
  99:     public override bool Add(CacheItem item, CacheItemPolicy policy)
 100:     {
 101:         if (item.Value == null)
 102:             return false;
 103:  
 104:         if (policy != null)
 105:             return base.Add(item, policy);
 106:  
 107:         try
 108:         {
 109:             Set(item, null);
 110:         }
 111:         catch (Exception)
 112:         {
 113:             return false;
 114:         }
 115:         return true;
 116:     }
 117:  
 118:     /// <summary>
 119:     /// When overridden in a derived class, gets the specified cache entry from the cache as an object.
 120:     /// </summary>
 121:     /// <param name="key">A unique identifier for the cache entry to get.</param>
 122:     /// <param name="regionName">Optional. A named region in the cache to which the cache entry was added, if regions are implemented. The default value for the optional parameter is null.</param>
 123:     /// <returns>
 124:     /// The cache entry that is identified by <paramref name="key"/>.
 125:     /// </returns>
 126:     public override object Get(string key, string regionName = null)
 127:     {
 128:         try
 129:         {
 130:             return _cacheFactory.GetDefaultCache().Get(GetKey(key, regionName));
 131:         }
 132:         catch (DataCacheException ex)
 133:         {
 134:             if (ex.ErrorCode == DataCacheErrorCode.RetryLater)
 135:             {
 136:                 // temporal failure, ignore and continue
 137:                 return null;
 138:             }
 139:  
 140:             throw;
 141:         }
 142:     }
 143:  
 144:     /// <summary>
 145:     /// When overridden in a derived class, checks whether the cache entry already exists in the cache.
 146:     /// </summary>
 147:     /// <param name="key">A unique identifier for the cache entry.</param>
 148:     /// <param name="regionName">Optional. A named region in the cache where the cache can be found, if regions are implemented. The default value for the optional parameter is null.</param>
 149:     /// <returns>
 150:     /// true if the cache contains a cache entry with the same key value as <paramref name="key"/>; otherwise, false.
 151:     /// </returns>
 152:     public override bool Contains(string key, string regionName = null)
 153:     {
 154:         return this.Get(key, regionName) != null;
 155:     }
 156:  
 157:     /// <summary>
 158:     /// When overridden in a derived class, gets the specified cache entry from the cache as a <see cref="T:System.Runtime.Caching.CacheItem"/> instance.
 159:     /// </summary>
 160:     /// <param name="key">A unique identifier for the cache entry to get.</param>
 161:     /// <param name="regionName">Optional. A named region in the cache to which the cache was added, if regions are implemented. Because regions are not implemented in .NET Framework 4, the default is null.</param>
 162:     /// <returns>
 163:     /// The cache entry that is identified by <paramref name="key"/>.
 164:     /// </returns>
 165:     public override CacheItem GetCacheItem(string key, string regionName = null)
 166:     {
 167:         var data = this.Get(key, regionName);
 168:         if (data != null)
 169:         {
 170:             return new CacheItem(key, data, regionName); ;
 171:         }
 172:  
 173:         return null;
 174:     }
 175:  
 176:     /// <summary>
 177:     /// When overridden in a derived class, removes the cache entry from the cache.
 178:     /// </summary>
 179:     /// <param name="key">A unique identifier for the cache entry.</param>
 180:     /// <param name="regionName">Optional. A named region in the cache to which the cache entry was added, if regions are implemented. The default value for the optional parameter is null.</param>
 181:     /// <returns>
 182:     /// An object that represents the value of the removed cache entry that was specified by the key, or null if the specified entry was not found.
 183:     /// </returns>
 184:     public override object Remove(string key, string regionName = null)
 185:     {
 186:         var data = this.Get(key, regionName);
 187:         if (data != null)
 188:         {
 189:             this._cacheFactory.GetDefaultCache().Remove(GetKey(key, regionName));
 190:             return data;
 191:         }
 192:  
 193:         return null;
 194:     }
 195:  
 196:     /// <summary>
 197:     /// When overridden in a derived class, inserts a cache entry into the cache.
 198:     /// </summary>
 199:     /// <param name="key">A unique identifier for the cache entry.</param>
 200:     /// <param name="value">The object to insert.</param>
 201:     /// <param name="policy">An object that contains eviction details for the cache entry. This object provides more options for eviction than a simple absolute expiration.</param>
 202:     /// <param name="regionName">Optional. A named region in the cache to which the cache entry can be added, if regions are implemented. The default value for the optional parameter is null.</param>
 203:     public override void Set(string key, object value, CacheItemPolicy policy, string regionName = null)
 204:     {
 205:         this.Set(new CacheItem(key, value, regionName), policy);
 206:     }
 207:  
 208:     /// <summary>
 209:     /// When overridden in a derived class, inserts a cache entry into the cache, specifying time-based expiration details.
 210:     /// </summary>
 211:     /// <param name="key">A unique identifier for the cache entry.</param>
 212:     /// <param name="value">The object to insert.</param>
 213:     /// <param name="absoluteExpiration">The fixed date and time at which the cache entry will expire.</param>
 214:     /// <param name="regionName">Optional. A named region in the cache to which the cache entry can be added, if regions are implemented. The default value for the optional parameter is null.</param>
 215:     public override void Set(string key, object value, DateTimeOffset absoluteExpiration, string regionName = null)
 216:     {
 217:         this.Set(new CacheItem(key, value, regionName), new CacheItemPolicy { AbsoluteExpiration = absoluteExpiration });
 218:     }
 219:  
 220:     /// <summary>
 221:     /// When overridden in a derived class, inserts the cache entry into the cache as a <see cref="T:System.Runtime.Caching.CacheItem"/> instance, specifying information about how the entry will be evicted.
 222:     /// </summary>
 223:     /// <param name="item">The cache item to add.</param>
 224:     /// <param name="policy">An object that contains eviction details for the cache entry. This object provides more options for eviction than a simple absolute expiration.</param>
 225:     public override void Set(CacheItem item, CacheItemPolicy policy)
 226:     {
 227:         if (item.Value == null) return;
 228:  
 229:         try
 230:         {
 231:             TimeSpan timeout = TimeSpan.FromMinutes(1);
 232:             if (policy != null)
 233:             {
 234:                 if (policy.SlidingExpiration != TimeSpan.Zero)
 235:                 {
 236:                     timeout = policy.SlidingExpiration;
 237:                 }
 238:                 else
 239:                 {
 240:                     timeout = policy.AbsoluteExpiration - DateTime.UtcNow;
 241:                 }
 242:             }
 243:  
 244:             if (policy == null)
 245:                 this._cacheFactory.GetDefaultCache().Put(GetKey(item.Key, item.RegionName), item.Value);
 246:             else
 247:                 this._cacheFactory.GetDefaultCache().Put(GetKey(item.Key, item.RegionName), item.Value, timeout);
 248:         }
 249:         catch (DataCacheException ex)
 250:         {
 251:             if (ex.ErrorCode == DataCacheErrorCode.RetryLater)
 252:             {
 253:                 // temporal failure, ignore and continue
 254:                 return;
 255:             }
 256:  
 257:             throw;
 258:         }
 259:     }
 260:  
 261:     public override long GetCount(string regionName = null)
 262:     {
 263:         throw new NotSupportedException();
 264:     }
 265:  
 266:     protected override IEnumerator<System.Collections.Generic.KeyValuePair<string, object>> GetEnumerator()
 267:     {
 268:         throw new NotSupportedException();
 269:     }
 270:  
 271:     public override IDictionary<string, object> GetValues(System.Collections.Generic.IEnumerable<string> keys, string regionName = null)
 272:     {
 273:         throw new NotSupportedException();
 274:     }
 275:  
 276:     public override CacheEntryChangeMonitor CreateCacheEntryChangeMonitor(System.Collections.Generic.IEnumerable<string> keys, string regionName = null)
 277:     {
 278:         throw new NotSupportedException();
 279:     }
 280:  
 281:     private static string GetKey(string key, string regionName)
 282:     {
 283:         if (string.IsNullOrWhiteSpace(regionName))
 284:         {
 285:             return key;
 286:         }
 287:         else
 288:         {
 289:             return string.Format(CultureInfo.InvariantCulture, RegionKeyTemplate, key, regionName);
 290:         }
 291:     }
 292:  
 293:     public void Dispose()
 294:     {
 295:         Dispose(true);
 296:         GC.SuppressFinalize(this);
 297:     }
 298:  
 299:     // The bulk of the clean-up code is implemented in Dispose(bool)
 300:     protected virtual void Dispose(bool disposing)
 301:     {
 302:         if (disposing)
 303:         {
 304:             // free managed resources
 305:             if (_cacheFactory != null)
 306:             {
 307:                 _cacheFactory.Dispose();
 308:                 _cacheFactory = null;
 309:             }
 310:         }
 311:     }
 312: }

Wednesday, April 25, 2012 #

If you see Nuget adding bindingRedirect to your app.config , when doing updates to existing assemblies, and if you feel this was not what you expected then read on.

Here is an example of a bindingRedirect added to the web.config file:

   1: <runtime>
   2:   <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
   3:     <dependentAssembly>
   4:       <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
   5:       <bindingRedirect oldVersion="1.0.0.0-2.0.0.0" newVersion="3.0.0.0" />
   6:     </dependentAssembly>
   7:   </assemblyBinding>
   8: </runtime>

An example of a bindingRedirect being added is when you first add FluentNHibernate package and then add the NHibernate package explicitly.
When FluentNHibernate is added to your project, it also adds a reference to NHibernate 3.1.4.0 as well, thus now when we add a reference to NHibernate explicitly it will update the NHibernate dll to 3.2.0.0 and since the NHibernate DLL versions are different, nuget also adds a bindingRedirect element to your projects app.config/web.config file as well.

Hence the workaround to this solution is not to add the NHibernate dll explicitly since FluentNHibernate depends on NHibernate and expects NHibernate 3.1.4.0 DLL to be present, if it does not find a bindingRedirect in the app.config file, it will not be able to load the NHibernate 3.2.0.0 dll.

Figured this out the hard way so hope this will help someone Smile


Wednesday, April 18, 2012 #

To use SQL Azure Federations with NHibernate we need to insure that we reuse the connection that was used for executing the USE Federation command.
Secondly we need to insure that we don’t enlist the “use Federation” command in a transaction.
For this purpose I have created a helper class named NHibernateSession which has a parameterized constructor which opens a connection and then associates that connection with the NHibernate ISession.

The NHibernateSession class looks like the following:

   1: public class NHibernateSession : IDisposable
   2:    {
   3:        private readonly ITransaction _transaction;
   4:        private readonly IDbConnection _connection;
   5:  
   6:        public NHibernateSession(bool beginTran, IDbConnection connection = null)
   7:        {
   8:            if (connection != null && connection.State == ConnectionState.Closed)
   9:            {
  10:                connection.Open();
  11:                _connection = connection;
  12:            }
  13:  
  14:            if (CurrentSessionContext.HasBind(NHibernateBootstrapper.SessionFactory))
  15:            {
  16:                NHibernateWorkspace.CurrentSession = NHibernateBootstrapper.SessionFactory.GetCurrentSession();
  17:            }
  18:            else
  19:            {
  20:                NHibernateWorkspace.CurrentSession = connection != null ? 
  21:                    NHibernateBootstrapper.SessionFactory.OpenSession(connection) : 
  22:                    NHibernateBootstrapper.SessionFactory.OpenSession();
  23:  
  24:                CurrentSessionContext.Bind(NHibernateWorkspace.CurrentSession);
  25:            }
  26:            if(beginTran)
  27:                _transaction = NHibernateWorkspace.CurrentSession.BeginTransaction();
  28:        }
  29:  
  30:        public NHibernateSession(int customerId, string connString) : this(false, new SqlConnection(connString))
  31:        {
  32:            var sql = string.Format("USE FEDERATION Customer_Federation(CustID = {0}) WITH RESET, FILTERING = ON;", customerId);
  33:            var query = NHibernateWorkspace.CurrentSession.CreateSQLQuery(sql);
  34:            query.UniqueResult();
  35:            _transaction = NHibernateWorkspace.CurrentSession.BeginTransaction();
  36:        }
  37:  
  38:        public NHibernateSession(): this(true)
  39:        {
  40:            
  41:        }
  42:  
  43:        public void Dispose()
  44:        {
  45:            Dispose(true);
  46:            GC.SuppressFinalize(this);
  47:        }
  48:  
  49:        // The bulk of the clean-up code is implemented in Dispose(bool)
  50:        protected virtual void Dispose(bool disposing)
  51:        {
  52:            if (disposing)
  53:            {
  54:                try
  55:                {
  56:                    if(_transaction != null)
  57:                        _transaction.Commit();
  58:                    if(_connection != null && _connection.State != ConnectionState.Closed)
  59:                        _connection.Close();
  60:                }
  61:                catch
  62:                {
  63:                    if (_transaction != null)
  64:                        _transaction.Rollback();
  65:                    throw;
  66:                }
  67:                finally
  68:                {
  69:                    // free managed resources
  70:                    CurrentSessionContext.Unbind(NHibernateBootstrapper.SessionFactory);
  71:                    NHibernateWorkspace.CurrentSession.Dispose();
  72:                }
  73:            }
  74:        }
  75:    }

Thus we could instantiate this NHibernateSession from within our Repositories/MVC Controllers as the following:
   1: var connstring = ConfigurationManager.ConnectionStrings["AdventureWorks2008R2EntitiesNoMARS"].ConnectionString;
   2: using (var ctx = new NHibernateSession(29825, connString))
   3: {
   4:     var sql = "SELECT COUNT(*) FROM Sales.SalesOrderDetail";
   5:     var query = NHibernateWorkspace.CurrentSession.CreateSQLQuery(sql);
   6:     var orderCount = query.UniqueResult();
   7: }

For code completeness I have included the code for the NHibernateBootstrapper which sets up the NHibernate Session Factory using Fluent NHibernate config:
   1: public class NHibernateBootstrapper
   2: {
   3:     private static readonly ISessionFactory SessionFactoryMember;
   4:     static NHibernateBootstrapper()
   5:     {
   6:         var allAssemblies = Assembly.GetExecutingAssembly().GetReferencedAssemblies().ToList();
   7:  
   8:         var autoConfig = new AutoMapConfiguration();
   9:         var persistenceModel = AutoMap.Assemblies(autoConfig, allAssemblies)
  10:             .Conventions.AddFromAssemblyOf<ClassConvention>()
  11:             .OverrideAll(m => m.IgnoreProperty("RowVersion"));
  12:  
  13:         foreach (var assembly in allAssemblies)
  14:         {
  15:             persistenceModel.UseOverridesFromAssembly(assembly);
  16:         }
  17:  
  18:         var connString = ConfigurationManager.ConnectionStrings[0].ConnectionString;
  19:  
  20:         var cfg = Fluently.Configure()
  21:             .Database(MySQLConfiguration.Standard.ConnectionString(connString)
  22:                           .Provider("NHibernate.Connection.DriverConnectionProvider, NHibernate")
  23:                           .Dialect("NHibernate.Dialect.MsSql2008Dialect")
  24:                           .Driver("NHibernate.Driver.SqlClientDriver")
  25:                           .ShowSql)
  26:             .CurrentSessionContext("NHibernate.Context.ThreadStaticSessionContext, NHibernate")
  27:             .Mappings(m =>
  28:                           {
  29:                               m.AutoMappings.Add(persistenceModel);
  30:                               foreach (var assembly in allAssemblies)
  31:                               {
  32:                                   m.FluentMappings.AddFromAssembly(assembly);
  33:                               }
  34:                           })
  35:             .BuildConfiguration();
  36:  
  37:         SessionFactoryMember = cfg.BuildSessionFactory();
  38:     }
  39:  
  40:     public static ISessionFactory SessionFactory
  41:     {
  42:         get { return SessionFactoryMember; }
  43:     }
  44: }

Wednesday, October 19, 2011 #

Policy injection block has been deprecated in Enterprise Library 5.0, however the ExceptionHandling application block contains ExceptionHandlingCallHandler which was usually found useful when used in conjunction with the Policy Injection App Block.
The purpose of this CallHandler is to handle exceptions using the policies defined in app.config/web.config for the ExceptionHandling app block.

One possible way of using the ExceptionHandlingCallHandler is to use the ExceptionHandlingCallHandler attribute on the methods that need Exception Handling. However the class must be enabled for interception by the Unity interceptors, since the ExceptionHandlingCallHandler attribute enables interception using the Unity Interception framework, hence the containing class should be enabled for interception by the Unity framework.

There are three possible ways of interception:
TransparentProxyInterceptor
InterfaceInterceptor
VirtualMethod interceptor

TransparentProxyInterceptor and InterfaceInterceptors are both interface interceptors and create a proxy around the class that needs interception.
InterfaceInterceptor is much better performing as compared to TransparentProxyInterceptors and hence we should choose InterfaceInterceptors except when we need intercept a class that is MarshalByRef object.
VirtualMethodInterceptor is a Type interceptor hence only works on abstract classes or concrete classes.
The following config shows how to enable a interface for interception:

<unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
  <sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, Microsoft.Practices.Unity.Interception.Configuration" />
  <typeAliases>
    <typeAlias alias="ICountryService" type="Aurionpro.SCMProFit.Business.Kernel.API.Masters.ICountryService, Aurionpro.SCMProFit.Business.Kernel.API" />
  </typeAliases>
  <containers>
    <container>
      <extension type="Interception" />
      <register type="ICountryService" mapTo="Aurionpro.SCMProFit.Business.Kernel.Masters.APIServices.CountryService, Aurionpro.SCMProFit.Business.Kernel">
        <interceptor type="InterfaceInterceptor" />
        <policyInjection />
      </register>       
    </container>
  </containers>
</unity>

In the above unity config, we first need to define the sectionExtension for interception:
<sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, Microsoft.Practices.Unity.Interception.Configuration" />
Then while registering the type with unity we also specify that we need this type to be intercepted. in the above example it uses InterfaceInterception for interception and uses the policyIntection Behavior for determining when the type should be intercepted.
Elsewhere in a common config I have defined the following policy :

<unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
  <sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, Microsoft.Practices.Unity.Interception.Configuration" />
  <containers>
    <container>
      <extension type="Interception" />
      <interception>
        <policy name="OperationContractPolicy">
          <matchingRule name="MatchOperationContract" type="Microsoft.Practices.Unity.InterceptionExtension.CustomAttributeMatchingRule,Microsoft.Practices.Unity.Interception">
            <constructor>
              <param name="attributeType" value="System.ServiceModel.OperationContractAttribute, System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" typeConverter="Microsoft.Practices.EnterpriseLibrary.Common.Configuration.AssemblyQualifiedTypeNameConverter, Microsoft.Practices.EnterpriseLibrary.Common"/>
              <param name="inherited">
                <value value="false"/>
              </param>
            </constructor>
          </matchingRule>
        </policy>          
      </interception>
    </container>
  </containers>
</unity>

In the above config I have defined a policy injection behavior which uses a CustomAttributeMatchingRule to check if a method is decorated with a “OperationContract” attribute and if so then the type is selected for Interception by unity. Thus now if the method in ICountryService is also decorated with the ExceptionHandlingCallHandler attribute, then the Exception Handling for such a method will now be enabled.
==============================================================================================================
However if we don’t want to decorate a method with the ExceptionHandlingCallHandler attribute and we need to enable ExceptionHandling purely using Configuration, then we can create a CallHandler which implements ICallHandler and reads the Exception Handling policy configuration from the app.config/web.config. The following shows such an implementation:

public class ExceptionCallHandler : ICallHandler
{
    // Fields
    private ExceptionPolicyImpl exceptionPolicy;
    private int order;
 
    public ExceptionCallHandler(string exceptionPolicyName, int order)
    {
        this.exceptionPolicy = UnityContainerFactory.Instance.Resolve<ExceptionPolicyImpl>(exceptionPolicyName);
        this.order = order;
    }
 
    // Methods
    public ExceptionCallHandler(ExceptionPolicyImpl exceptionPolicy)
    {
        this.exceptionPolicy = exceptionPolicy;
    }
 
    public ExceptionCallHandler(ExceptionPolicyImpl exceptionPolicy, int order)
        : this(exceptionPolicy)
    {
        this.order = order;
    }
 
    public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
    {
        if (input == null)
        {
            throw new ArgumentNullException("input");
        }
        if (getNext == null)
        {
            throw new ArgumentNullException("getNext");
        }
        IMethodReturn return2 = getNext()(input, getNext);
        if (return2.Exception != null)
        {
            try
            {
                if (!this.exceptionPolicy.HandleException(return2.Exception))
                {
                    return2.ReturnValue = null;
                    return2.Exception = null;
                    if (input.MethodBase.MemberType == MemberTypes.Method)
                    {
                        MethodInfo methodBase = (MethodInfo)input.MethodBase;
                        if (methodBase.ReturnType != typeof(void))
                        {
                            return2.Exception = new InvalidOperationException(Resources.CantSwallowNonVoidReturnMessage);
                        }
                    }
                }
            }
            catch (Exception exception)
            {
                return2.Exception = exception;
            }
        }
        return return2;
    }
 
    // Properties
    public ExceptionPolicyImpl ExceptionPolicy
    {
        get
        {
            return this.exceptionPolicy;
        }
    }
 
    public int Order
    {
        get
        {
            return this.order;
        }
        set
        {
            this.order = value;
        }
    }
}

We need this class since we need an instance of ExceptionPolicyImpl and I used the same logic to create such an instance, as is specified in the ExceptionHandlingCallHandlerAttribute implementation.
Once we have this, just call this CallHandler to the unity config and all methods that satisfy the MatchingRule (in our case the CustomAttributeMatchingRule which looks for presence of OperationContract attribute on a method) would then call this ExceptionCallHandler. the example config will look like the following:

<unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
  <sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, Microsoft.Practices.Unity.Interception.Configuration" />
  <containers>
    <container>
      <extension type="Microsoft.Practices.EnterpriseLibrary.Common.Configuration.Unity.EnterpriseLibraryCoreExtension, Microsoft.Practices.EnterpriseLibrary.Common" />
      <extension type="Interception" />
      <interception>
        <policy name="OperationContractPolicy">
          <matchingRule name="MatchOperationContract" type="Microsoft.Practices.Unity.InterceptionExtension.CustomAttributeMatchingRule,Microsoft.Practices.Unity.Interception">
            <constructor>
              <param name="attributeType" value="System.ServiceModel.OperationContractAttribute, System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" typeConverter="Microsoft.Practices.EnterpriseLibrary.Common.Configuration.AssemblyQualifiedTypeNameConverter, Microsoft.Practices.EnterpriseLibrary.Common"/>
              <param name="inherited">
                <value value="false"/>
              </param>
            </constructor>
          </matchingRule>
          <callHandler name="EFCallHandler" type="Aurionpro.SCMFramework.Common.Repository.EntityFramework.Interceptor.EntityFrameworkCallHandler,Aurionpro.SCMFramework.Common">
            <constructor>
              <param name="order" value="10"/>
            </constructor>
          </callHandler>
          <callHandler name="ExceptionHandlingCallHandler" type="Aurionpro.SCMFramework.Common.Repository.EntityFramework.Interceptor.ExceptionCallHandler,Aurionpro.SCMFramework.Common">
            <constructor>
              <param name="exceptionPolicyName" value="UIExceptionPolicy"/>
              <param name="order" value="1"/>
            </constructor>
          </callHandler>
        </policy>          
      </interception>
    </container>
  </containers>
</unity>

In the above config we have explicitly added the following extension:
<extension type="Microsoft.Practices.EnterpriseLibrary.Common.Configuration.Unity.EnterpriseLibraryCoreExtension, Microsoft.Practices.EnterpriseLibrary.Common" />
and then added a reference to the created ExceptionCallHandler class do perform exception handling using the “UIPolicyException” policy . A sample Exception Handling policy looks like the following:

<exceptionHandling>
  <exceptionPolicies>
    <add name="UIExceptionPolicy">
      <exceptionTypes>
        <add type="System.Exception, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" postHandlingAction="ThrowNewException" name="Exception">
          <exceptionHandlers>
            <add name="Wrap Handler" type="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.WrapHandler, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling, Version=5.0.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"  
                 exceptionMessage="Exception while updating entity"    
                 wrapExceptionType="Aurionpro.SCMFramework.Common.Repository.Exceptions.RepositoryException, Aurionpro.SCMFramework.Common,Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
          </exceptionHandlers>
        </add>
      </exceptionTypes>
    </add>
  </exceptionPolicies>
</exceptionHandling>

Tuesday, October 18, 2011 #

When using the storage client library to access Azure Storage, it is recommended that we make use of the Async calls to execute queries against the Azure Tables/Blobs.
TableClient and BlobClient expose methods to execute queries asynchronously, for e.g.

blobClient.BeginListContainersSegmented : which retrieves the list of Blob Containers in our storage.
cloudTableClient.BeginListTablesSegmented() : which retrieves the list of tables in Azure strorage
and many more


Then there is CloudTableQuery class which exposes the BeginExecuteSegmented method which enables us to execute queries asynchronously.

The following example shows how to get the number of rows in a Azure Table.

   1: var context = new TableServiceContext(this.storageAccount.TableEndpoint.ToString(), this.storageAccount.Credentials);
   2: var query = context.CreateQuery<T>(this.tableName).AsTableServiceQuery();
   3:  
   4: if (condition != null)
   5:     query = Query.Where(condition).AsTableServiceQuery();
   6:  
   7: var results = new List<T>();
   8: if (query != null)
   9: {
  10:     //Using Storage Client Library Async API to execute query
  11:     using (var mre = new System.Threading.ManualResetEvent(false))
  12:     {
  13:         query.BeginExecuteSegmented((result) =>
  14:                                         {
  15:                                             var resultSegment =
  16:                                                 query.EndExecuteSegmented(result);
  17:                                             results.AddRange(resultSegment.Results);
  18:                                             while (resultSegment.HasMoreResults)
  19:                                             {
  20:                                                 resultSegment = resultSegment.GetNext();
  21:                                                 results.AddRange(resultSegment.Results);
  22:                                             }
  23:                                             mre.Set();
  24:                                         }, null);
  25:         mre.WaitOne();
  26:     }
  27: }
  28: return results.Count;

Note that currently with version 1.5 of the Azure SDK, there are some instances when the AsTableServiceQuery() extension method throws an exception complaining that the query parameter passed to the CloudTableQuery<T> constructor cannot be null.
This happens when the query is returning the entire table with no filter conditions.
At these times the cast to DataServiceQuery<T> fails and AsTableServiceQuery() throws an exception.
To get around this limitation cast the IQueryable<T> to CloudTableQuery<T> manually instead of calling the AsTableServiceQuery() extension.

   1: var context = new TableServiceContext(this.account.TableEndpoint.ToString(), this.account.Credentials);
   2: var query1 = context.CreateQuery<T>(this.tableName).AsTableServiceQuery();
   3: // if we call AsTableServiceQuery() again on query1 the "Variable cannot be null" exception is thrown
   4: var query = query1 as CloudTableQuery<AzureDummy>;
   5: query.BeginExecuteSegmented();

Here is an excellent post about using Asunc API for working with blobs : Accessing Blobs using Async API.

There some excellent posts by Neil Mackenzie on async API as well (which shows how to use BeginExecute() on DataServiceQuery<T> ): Queries in Azure Tables


Thursday, September 22, 2011 #

In Windows Azure, we have the DiagnosticMonitorTraceListener which can be used for writing diagnostics to Local resource (like a local storage in the Worker or Web Role) which can then be ultimately stored in Windows Azure Table/Blob storage (transferred automatically by the Diagnostics Monitor in Windows Azure based on config settings).

We could either configure the Diagnostic Monitor using Code (in Role Startup) or we can use a config file for the same (called diagnostics.wadcfg). The code configuration for enabling transfer of Logs to Azure table storage looks something like this:

   1: String wadConnectionString = "Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString";
   2: String customContainerName = "wad-custom-container";
   3:  
   4: DiagnosticMonitorConfiguration dmc = DiagnosticMonitor.GetDefaultInitialConfiguration();
   5:  
   6: LocalResource localResource = RoleEnvironment.GetLocalResource(localResourceName);
   7: String logPath = Path.Combine(localResource.RootPath, "Logs");
   8: DirectoryConfiguration directoryConfiguration = new DirectoryConfiguration()
   9: {
  10:     Container = customContainerName,
  11:     DirectoryQuotaInMB = localResource.MaximumSizeInMegabytes,
  12:     Path = logPath
  13: };
  14: dmc.Directories.DataSources.Add(directoryConfiguration);
  15: dmc.Directories.ScheduledTransferPeriod = TimeSpan.FromMinutes(1);
  16:  
  17: dmc.Logs.BufferQuotaInMB = 100;
  18: dmc.Logs.ScheduledTransferPeriod = TimeSpan.FromMinutes(1);
  19: dmc.Logs.ScheduledTransferLogLevelFilter =  LogLevel.Verbose;
  20: DiagnosticMonitor.Start(wadConnectionString, dmc);
If we need to use a configuration file instead the config file needs to be placed in the %RoleEntryPoint% folder in the case of web roles or within %RoleEntryPoint%\bin folder for WorkerRoles. Alternatively in Visual Studio, just include this diagnostics.wadcfg file in the root folder and set the following properties:

diagnostics.wadcfg

If we use the config file, then we don’t need any custom code in the Role Startup. The config file would look like the following:

   1: <DiagnosticMonitorConfiguration xmlns="http://schemas.microsoft.com/ServiceHosting/2010/10/DiagnosticsConfiguration" configurationChangePollInterval="PT1M" overallQuotaInMB="4096">
   2:   <DiagnosticInfrastructureLogs bufferQuotaInMB="100" scheduledTransferLogLevelFilter="Verbose" scheduledTransferPeriod="PT1H"/>
   3:   <WindowsEventLog bufferQuotaInMB="100" scheduledTransferLogLevelFilter="Verbose" scheduledTransferPeriod="PT1H">
   4:     <DataSource name="Application!*"/>
   5:   </WindowsEventLog>
   6:   <Logs bufferQuotaInMB="100" scheduledTransferLogLevelFilter="Verbose" scheduledTransferPeriod="PT1M"/>
   7:   <Directories bufferQuotaInMB="1024" scheduledTransferPeriod="PT1M">
   8:  
   9:     <!-- These three elements specify the special directories that are set up for the log types -->
  10:     <CrashDumps container="wad-crash-dumps" directoryQuotaInMB="256"/>
  11:     <FailedRequestLogs container="wad-frq" directoryQuotaInMB="256"/>
  12:     <IISLogs container="wad-iis-test" directoryQuotaInMB="256"/>
  13:  
  14:     <DataSources>
  15:       <DirectoryConfiguration container="wad-custom-container" directoryQuotaInMB="20">
  16:         <!--LocalResource specifies a path relative to a local resource defined in the service definition-->
  17:         <LocalResource name="CustomLoggingLocation" relativePath="Logs"/>
  18:       </DirectoryConfiguration>
  19:     </DataSources>
  20:   </Directories>
  21:  
  22:   <PerformanceCounters bufferQuotaInMB="100" scheduledTransferPeriod="PT20M">
  23:     <!-- The counter specifier is in the same format as the imperative diagnostics configuration API -->
  24:     <PerformanceCounterConfiguration counterSpecifier="\Processor(_Total)\% Processor Time" sampleRate="PT10S"/>
  25:   </PerformanceCounters>
  26: </DiagnosticMonitorConfiguration>

This configuration is very similar to the default configuration that is stored in “wad-control-container” blob in Azure Blob storage for every deployment of our app.
Additionally, if we already have some custom configuration in “wad-control-container” we could get an instance of this configuration using RoleInstanceDiagnosticManager and then Update this configuration with the changes we need. Here is an example of doing the same:

   1: CloudStorageAccount cloudStorageAccount = CloudStorageAccount.Parse(RoleEnvironment.GetConfigurationSettingValue(wadConnectionString));
   2: var roleInstanceDiagnosticManager =
   3:     new RoleInstanceDiagnosticManager(cloudStorageAccount, RoleEnvironment.DeploymentId,
   4:                                       RoleEnvironment.CurrentRoleInstance.Role.Name,
   5:                                       RoleEnvironment.CurrentRoleInstance.Id);
   6:  
   7: DiagnosticMonitorConfiguration dmc = roleInstanceDiagnosticManager.GetCurrentConfiguration();
   8: LocalResource localResource = RoleEnvironment.GetLocalResource(localResourceName);
   9: String logPath = Path.Combine(localResource.RootPath, "Logs");
  10: DirectoryConfiguration directoryConfiguration = new DirectoryConfiguration()
  11: {
  12:     Container = customContainerName,
  13:     DirectoryQuotaInMB = localResource.MaximumSizeInMegabytes,
  14:     Path = logPath
  15: };
  16: dmc.Directories.DataSources.Add(directoryConfiguration);
  17: dmc.Directories.ScheduledTransferPeriod = TimeSpan.FromMinutes(1);
  18:  
  19: dmc.Logs.BufferQuotaInMB = 100;
  20: dmc.Logs.ScheduledTransferPeriod = TimeSpan.FromMinutes(1);
  21: dmc.Logs.ScheduledTransferLogLevelFilter =  LogLevel.Verbose;
  22: roleInstanceDiagnosticManager.SetCurrentConfiguration(dmc);

Using DiagnosticMonitorTraceListener with Logging Application Block

We can use the same DiagnosticMonitorTraceListener as a TraceListener in Logging Application Block, the config for the same looks like this:

   1: <listeners>
   2:   <add type="Microsoft.WindowsAzure.Diagnostics.DiagnosticMonitorTraceListener, Microsoft.WindowsAzure.Diagnostics, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
   3:       listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.SystemDiagnosticsTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
   4:        formatter="Text Formatter"
   5:        name="AzureDiagnostics">
   6:   </add>
   7: </listeners>

Then in C# code we could use such code for Logging:

   1: private static void Log(string module, string message, TraceEventType severity, params object[] args)
   2: {
   3:     string moduleSeverity = ConfigurationManager.AppSettings[module] ?? "";
   4:     if ((string.IsNullOrWhiteSpace(moduleSeverity) || moduleSeverity.Equals(severity.ToString().ToLower(), StringComparison.OrdinalIgnoreCase))
   5:         && Microsoft.Practices.EnterpriseLibrary.Logging.Logger.IsLoggingEnabled())
   6:     {
   7:         var msg = string.Format(message, args);
   8:         Microsoft.Practices.EnterpriseLibrary.Logging.Logger.Write(msg, module, 1, 0, severity);
   9:     }
  10: }

The Sample configuration for Logging Application Block would look something like the following:

   1: <configuration>
   2:   <configSections>
   3:     <section name="loggingConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.LoggingSettings, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="true" />
   4:   </configSections>
   5:   <loggingConfiguration name="" tracingEnabled="true" defaultCategory="General">
   6:     <listeners>
   7:       <add name="Event Log Listener" type="Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.FormattedEventLogTraceListener, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
   8:           listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.FormattedEventLogTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
   9:           source="SmartSAPConn" formatter="Text Formatter" log="" machineName="."
  10:           traceOutputOptions="None" />
  11:       <add type="Microsoft.WindowsAzure.Diagnostics.DiagnosticMonitorTraceListener, Microsoft.WindowsAzure.Diagnostics, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
  12:           listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.SystemDiagnosticsTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
  13:            formatter="Text Formatter"
  14:            name="AzureDiagnostics">
  15:       </add>
  16:     </listeners>
  17:     <formatters>
  18:       <add type="Microsoft.Practices.EnterpriseLibrary.Logging.Formatters.TextFormatter, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
  19:           template="Timestamp: {timestamp}{newline}&#xA;Message: {message}{newline}&#xA;Category: {category}{newline}&#xA;Priority: {priority}{newline}&#xA;EventId: {eventid}{newline}&#xA;Severity: {severity}{newline}&#xA;Title:{title}{newline}&#xA;Machine: {localMachine}{newline}&#xA;App Domain: {localAppDomain}{newline}&#xA;ProcessId: {localProcessId}{newline}&#xA;Process Name: {localProcessName}{newline}&#xA;Thread Name: {threadName}{newline}&#xA;Win32 ThreadId:{win32ThreadId}{newline}&#xA;Extended Properties: {dictionary({key} - {value}{newline})}"
  20:           name="Text Formatter" />
  21:     </formatters>
  22:     <categorySources>
  23:       <add switchValue="All" name="General">
  24:         <listeners>
  25:           <add name="AzureDiagnostics" />
  26:         </listeners>
  27:       </add>
  28:     </categorySources>
  29:     <specialSources>
  30:       <allEvents switchValue="All" name="All Events" />
  31:       <notProcessed switchValue="All" name="Unprocessed Category" />
  32:       <errors switchValue="All" name="Logging Errors &amp; Warnings">
  33:         <listeners>
  34:           <add name="AzureDiagnostics" />
  35:         </listeners>
  36:       </errors>
  37:     </specialSources>
  38:   </loggingConfiguration>  
  39: </configuration>

Once we do this, at the configured interval in diagnostics.wadcfg file, the log records will get recorded in Azure table storage in “WADLogsTable” which gets created automatically by the DiagnosticsMonitor.
If we used Directory Logging then that would get persisted in Blob storage in a custom Blob container (in our case it would be wad-custom-container)


Thursday, August 18, 2011 #

While developing applications for Windows Azure, we are all aware that we need to create Web and Worker Roles and use the Azure Compute Emulator (previously known as the Development Fabric) for running and testing applications in the local IIS server.

However to run unit tests against libraries that are being consumed from your web/worker roles we need to perform some preliminary steps before we can start using the CloudStorageAccount class within our Unit Tests.

The First step is to start the Storage Service if it is not already started which can be done in a method decorated with the AssemblyInitialze attribute.
The Second step is to call the CloudStorageAccount.SetConfigurationSettingPublisher method from a method decorated with the ClassInitialize attribute, so that we can then successfully use the CloudStorageAccount.FromConfigurationSetting("DataConnectionString") call from within any of the TestMethods.

The code to start the Storage Service can be something like the following:

   1: [AssemblyInitialize]
   2: public static void AssemblyInitialize(TestContext context)
   3: {
   4:     var count = Process.GetProcessesByName("DSService").Length;
   5:     if (count == 0)
   6:     {
   7:         var start = new ProcessStartInfo
   8:         {
   9:             Arguments = "/devstore:start",
  10:             FileName = @"C:\Program Files\Windows Azure SDK\v1.4\bin\csrun.exe"
  11:         };
  12:  
  13:         var proc = new Process { StartInfo = start };
  14:         proc.Start();
  15:         proc.WaitForExit();
  16:     }
  17: }

Before we can start using the _storageAccount from within our unit tests we need the following code to be configured and setup:

First in the app.config file in the AppSettings section we need to add the following entry:

   1: <configuration>
   2:   <appSettings>
   3:     <add key="DataConnectionString" value="UseDevelopmentStorage=true" />
   4:   </appSettings>
   5: </configuration>

Then in the ClassInitialize static method we need the following code:

   1: [ClassInitialize()]
   2: public static void Init(TestContext testContext)
   3: {
   4:     CloudStorageAccount.SetConfigurationSettingPublisher((configName, configSetter) =>
   5:     {
   6:         var connectionString = ConfigurationManager.AppSettings[configName];
   7:         configSetter(connectionString);
   8:     });
   9: }

Finally in the TestMethod() we can use the _storageAccount and work directly against the Azure table/blob/queue storage as shown below:

   1: [TestMethod]
   2: public void FileExists(string pathWithFileName)
   3: {
   4:     pathWithFileName = pathWithFileName.Replace("\\", "/");
   5:     var storageAccount = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");
   6:     _blobClient = storageAccount.CreateCloudBlobClient();
   7:     _blobClient.Timeout = new TimeSpan(1, 0, 0);
   8:     _blobClient.ParallelOperationThreadCount = 2;
   9:  
  10:     // Get the container
  11:     _blobContainer = _blobClient.GetContainerReference(_blobContainerName);
  12:     //Get the file from the blob container
  13:     var blob = _blobContainer.GetBlobReference(pathWithFileName);
  14:     Assert.Istrue(blob.Exists());
  15: }

Wednesday, February 16, 2011 #

Consider the following:
We have an account named MYDOMAIN\eholz. This accounts Active Directory Login Name changes to MYDOMAIN\eburrell
Now this user was a active user in a Sharepoint 2010 team Site, and had a userProfile using the Account name MYDOMAIN\eholz.
Since the AD LoginName changed to eburrell hence we need to update the Sharepoint User (SPUser object) as well update the userprofile to reflect the new account name.
To update the Sharepoint User LoginName we can run the following stsadm command on the Server:

STSADM –o migrateuser –oldlogin MYDOMAIN\eholz –newlogin MYDOMAIN\eburrell –ignoresidhistory

However to update the Sharepoint 2010 UserProfile, i first tried running a Incremental/Full Synchronization using the User Profile Synchronization service… this did not work. To enable me to update the AccountName field (which is a read only field) of the UserProfile, I had to first delete the User Profile for MYDOMAIN\eholz and then run a FULL Synchronization using the User Profile Synchronization service which synchronizes the Sharepoint User Profiles with the AD profiles.

Update: if you just run the STSADM –o migrateuser command… the profile also gets updated automatically. so all you need is to run the stsadm –o migrate user command and you dont need to delete and recreate the User Profile


If you facing the issue that the web Analytics Reports in SharePoint 2010 Central Administration is not updating data.

When you go to your site > site settings > Site Web Analytics reports or Site Collection Analytics reports 
You get old data as in the ribbon displayed "Data Last Updated: 12/13/2010 2:00:20 AM"

  • Please insure that the following things are covered:

    Insure that Usage and Data Health Data Collection service is configured correctly.
    Log Collection Schedule is configured correctly
    Microsoft Sharepoint Foundation Usage Data Import and Microsoft SharePoint Foundation Usage Data Processing Timer jobs are configured to run at regular intervals
    One last important Timer job is the Web Analytics Trigger Workflows Timer Job insure that this timer job is enabled and scheduled to run at regular intervals (for each site that you need analytics for).

    After you have insured that the web analytics service configuration is working fine and the Usage Data Import job is importing the *.usage files from the ULS LOGS folder into the WSS_Logging database, and that all the required timer jobs are running as expected… wait for a day for the report to get updated… the report gets updated automatically at 2:00 am in the morning… and i could not find a way to control the schedule for this report update job.

    So be sure to wait for a day before giving up :)

Monday, November 8, 2010 #

If you generate CAML using LINQ to SharePoint in Visual Studio 2010 then you might see this bug popup:

If you are writing a CAML query to filter records based on Date and Time, and this query is generated using LINQ To SharePoint then you will get the following CAML query generated:

<View>
  <Query>
    <Where>
        <And>
          <Eq>
            <FieldRef Name='Title' />
            <Value Type='Text'>{0}</Value>
          </Eq>
          <Lt>
            <FieldRef Name='QuoteTime' IncludeTimeValue='TRUE' />
            <Value Type='DateTime>{1}</Value>
          </Lt>
        </And>
     </Where>
  </Query>
  <RowLimit Paged='TRUE'>100</RowLimit>
</View>

However the above is incorrect since the IncludeTimeValue Attribute is on the wrong element. The correct CAML query is as follows:

<View>
  <Query>
    <Where>
        <And>
          <Eq>
            <FieldRef Name='Title' />
            <Value Type='Text'>{0}</Value>
          </Eq>
          <Lt>
            <FieldRef Name='QuoteTime' />
            <Value Type='DateTime' IncludeTimeValue='TRUE'>{1}</Value>
          </Lt>
        </And>
     </Where>
  </Query>
  <RowLimit Paged='TRUE'>100</RowLimit>
</View>

Note that the IncludeTimeValue attribute is on the Value Element and not the FieldRef element. Thus if you need to filter records based on Date & Time then include the “IncludeTimeValue” attribute on the Value Element.


Friday, July 16, 2010 #

Here is the fix for the same:

1-Locate the Outlook Temporary Items folder by opening the Registry and locating HKEY_CURRENT_USER\Software\Microsoft\Office\11.0\Outlook\Sec urity\OutlookSecureTempFolder Navigate to the value of this Key. It should be something like: %USERPROFILE%\Local Settings\Temporary Internet Files\OLK3D\ where OLK3D is some randomly generated string that always starts with OLK
2-Quit Outlook
3-Delete the contents of the folder
4-Launch Outlook


Wednesday, June 23, 2010 #

Some of the new Features in EF v4 are :

context.ContextOptions.LazyLoadingEnabled is “true” by default.
What this means is that if you access a Navigation Property (which returns either a EntityCollection or a EntityReference) of an Entity and if that Navigated Entity (or Entity collection) is not found in the ObjectContext then the ObjectContext automatically loads it when the NavigationProperty is accessed. This means additional round trip to the database for each Navigated entity.
If you need to turn off this LazyLoadingEnabled flag on the ObjectContext set the LazyLoadingEnabled flag in the OnContextCreated() partial method of the PEFEntities partial class you created like so :

   1: public partial class PEFEntities
   2: {
   3:     partial void OnContextCreated()
   4:     {
   5:         this.ContextOptions.LazyLoadingEnabled = false;
   6:     }
   7: }

ObjectSet<TEntity>
In EntityFramework v4.0 when you execute a ObjectQuery<> it returns a ObjectSet of Entities. In earlier versions of Entity Framework, the ObjectQuery when executed returned a ObjectQuery itself which we could then iterate through to get results.

context.ExecuteStoreCommand

This command can be used to execute SQL/PSQL commands that don't return any values for e.g. insert/delete statements.

   1: using (var context = new EFRecipesEntities())
   2: {
   3:     context.ExecuteStoreCommand("delete from chapter10.Product");
   4:     context.ExecuteStoreCommand("insert into chapter10.Product values ('Chai', 'Beverage')");
   5: }

context.ExecuteStoreQuery<TElement>
If you need to execute a SQL/PSQL that returns record sets then use context.ExecuteStoreQuery<TElement> where TElement can be an existing Entity in the CSDL of the EDMX file, or if the result does not map to an existing Entity in the CSDL then use context.ExecuteStoreQuery<DbDataRecord> to iterate over the columns of the returned results manually using indexers on DbDataRecord to access column values. Note that context.ExecuteStoreQuery<> returns a ObjectResult<TElement> which be iterated over only once as opposed to ObjectSet<T> or ObjectQuery<T> which can be iterated over multiple times.

   1: using (var context = new EFRecipesEntities())
   2: {
   3:     string sql = "select * from Chapter3.Student where Degree = @Major";
   4:     var args = new DbParameter[] { new SqlParameter { ParameterName = "Major", Value = "Masters" } };
   5:     var students = context.ExecuteStoreQuery<Student>(sql, args);
   6: }


context.Translate<>
EF v4 does not provide a DIRECT way to iterate over Multiple result sets returned from a Stored Proc/ SQL Query. One solution is to use SqlCommand object to execute and return a SQLDataReader which contains multiple result sets and pass this datareader to context.Translate<> method which materialzes the datareader results into Entity objects. If you use the correct overload of context.Translate<>(reader, entitySetName, MergeOption) then Translate also fixes relationship spans automatically (i.e. fixes associations between related entities automatically).
Here is an example :

   1: using (var context = new EFRecipesEntities())
   2: {
   3: var cs = @"Data Source=.;Initial Catalog=EFRecipes;Integrated Security=True";
   4: var conn = new SqlConnection(cs);
   5: var cmd = conn.CreateCommand();
   6: cmd.CommandType = System.Data.CommandType.StoredProcedure;
   7: cmd.CommandText = "Chapter3.GetBidDetails";
   8: conn.Open();
   9: var reader = cmd.ExecuteReader(CommandBehavior.CloseConnection);
  10: var jobs = context.Translate<Job>(reader, "Jobs",
  11: MergeOption.AppendOnly).ToList();
  12: reader.NextResult();
  13: context.Translate<Bid>(reader, "Bids", MergeOption.AppendOnly).ToList();
  14:     foreach (var job in jobs)
  15:     {
  16:         Console.WriteLine("\nJob: {0}", job.JobDetails);
  17:         foreach (var bid in job.Bids)
  18:         {
  19:         Console.WriteLine("\tBid: {0} from {1}",
  20:         bid.Amount.ToString("C"), bid.Bidder);
  21:         }
  22:     }
  23: }
If we do not use the correct overload of context.Translate<> then, in the above example the Bids would never get materialized into objects since there will not exist any association between jobs and bids. Also note that we do not need to call .ToList() on the first context.Translate<Job>() method before we can call reader.NextResult(), since context.Translate<> merely returns ObjectResult<Job> which needs to be completely iterated over before NextResult() call can succeed.
Translate() requires that the DbDataReader have columns that match each property on the entity. This matching is done using simple name matching. If a column name can’t be matched to a property, Translate() will fail.

DefaultIfEmpty() is now supported with EF v4.

In earlier versions of Entity Framework DefaultIfEmpty() method was not supported on ObjectQueries hence it was difficult to create LinqToEntities queries which was a Left JOIN across collections. In EF v4 we surely have this capability, so left joins are easier to implement and use in LinqToEntities. Here is an example:
   1: var products = from p in context.Products
   2:     join t in context.TopSellings on
   3:     p.ProductId equals t.ProductId into g
   4:     from tps in g.DefaultIfEmpty()
   5:     orderby tps.Rating descending
   6:     select new
   7:     {
   8:         Name = p.Name,
   9:         Rating = tps.Rating == null ? 0 : tps.Rating
  10:     };
CreateSourceQuery()
CreateSourceQuery() to create a ObjectQuery() from a EntityCollection or EntityReference to delay load Navigation properties of Entities.
If a Entity “address” has a Navigation Property which returns a EntityReference  “contact” or EntityCollection “Streets” and if LazyLoadingEnabled =  false, then inorder to insure that the EntityReference/EntityCollection is delay loaded we can either call the .Load() method on the
“address” entity’s navigation property. The other option is to call CreateSourceQuery() on the navigation property and then access the EntityReference or iterate over the EntityCollection.
The advantage of using CreateSourceQuery() is that we can add further QueryBuilder methods like “Include” to the ObjectQuery<> created by the CreateSourceQuery() call. for e.g. address.Contact.CreateSourceQuery().Include(“Orders”) will not only load the contact EntityReference, but it will also load all Orders for the contact.
The other advantage of CreateSourceQuery() is that we can use filters to get only certain entries from the EntityCollection (as shown below).
Yet another advantage of using CreateSourceQuery() is that we can attach range of Entities to a EntityCollection, instead of attaching 1 entity at a time.
   1: var cust=context.Contacts.OfType<Customer>().First(); 
   2: var sq = cust.Reservations.CreateSourceQuery().Where(r => r.ReservationDate > new DateTime(2008,1,1)); 
   3: cust.Reservations.Attach(sq); 
Gotchas with using the .Include() Query Builder method:
    If the query on which the .Include() builder method has been used does projections or group joins then the Include with be ignored. Group Joins changes the result type of the query hence the Include() is ignored.
    Thus Include applies only to final query results. if Include is used in a subquery, join, or nested “from” clause it is ignored.
    Include() method is a extension method only on the ObjectQuery<T>. Thus if you need to execute the Include() extension method against a IQueryable<T> then we need to cast it to ObjectQuery<T> first.
    The Query Path used within a Include() must begin from a Navigation property of the Entity on which the Include is being used.

IsLoaded Property, Clear() and Load() methods.
When you call Clear() method on Navigation Property which is a EntityCollection, then the cleared entities do still remain in the ObjectContext, its just that they are no longer connected to the parent entity. for e.g. order.OrderItems.Clear() will empty the OrderItems collection of the order Entity, however the OrderItem Entities themselves will still remain in the ObjectContext. Thus if you need to reconnect the OrderItem entities for the order then we need to call order.OrderItems.Load(MergeOption.OverwtiteChanges) instead of order.Orderitems.Load() since the default merge option is MergeOption.AppendOnly.

If you are manually doing deferred loading then always used .IsLoaded Property on the Entity you are trying to Load before explicitly defer loading of the Entity.
Another thing to note about the IsLoaded Property is that say for e.g. for Order with OrderId 1 there are no OrderItems. Thus when you call .Load() on the order.OrderItems.Load() then the OrderItems collection will be null, however note that the .IsLoaded property of OrderItems will be true.

When you use the CreateSourceQuery() method to grab the query for loading the entity or entity collection, Entity Framework will not set IsLoaded when the query is executed

If a parent Entity has been Loaded using a specific MergeOption then all the navigation entities must also be loaded with the same MergeOption else the deferred Loading of the Navigation entities will fail.

Relationship-span and Associations
When EF loads an Entity it also loads any “associations” that are 0..1 or 1..1.”associations” are first-class objects like entities. EF creates 3 ObjectStateEntries on ObjectStateManager, 1 for the Entity, 1 for the Association and 1 for the Stub for the other end of the association that is not yet loaded. The stub has a valid EntityKey even though the entity itself has not yet been loaded.
When that other entity is loaded the first entities stub is automatically populated with this other entity which just got loaded and thus completes the association.
This automatic loading of the stub entity is called relationship-span.

QueryView… EntitySQL queries written in the MSL … when to use QueryViews:
QueryViews can be very handy when you need to create Entities using more complex Filter conditions.
Finally to be able to use these Entities created using QueryViews to be updateable use Stored procedures to map to the  Insert, Update and Delete Functions of each entity being created using the QueryView.

Using ObjectStateManager to retrieve Entities from the ObjectContext that not yet saved to the database:
Use the following code to retrieve all Entities from the OSM (ObjectStateManager) that are not in the Detached state (i.e. in the Added, Modified, Deleted or Unchanged states):

   1: public static class StateManagerExtensions
   2: {
   3: public static IEnumerable<T> GetEntities<T>(this ObjectStateManager manager)
   4:     {
   5:     var entities = manager
   6:     .GetObjectStateEntries(~EntityState.Detached)
   7:     .Where(entry => !entry.IsRelationship && entry.Entity != null)
   8:     .Select(entry => entry.Entity).OfType<T>();
   9:     return entities;
  10:     }
  11: }

Note that when you run queries directly against the ObjectContext to get Entities ( for e.g. context.Technicians.Include(“ServiceCalls”), they return only entities that currently exist in the database. It is important to note that when you add or delete entities from the object context, these changes are not reflected in results of queries against the object context (context.Technicians). These queries represent entities as they exist in the database, not what currently exist in the object context.

Attach() vs AddObject().
We can use AddObject() on the EntitySet or the ObjectContext to add new Entities to the collection. However we can also use Attach() to add new entities to the collection. However when adding Entities using Attach is a 2 step process. First we need to call EntitySet.Attach() to attach the entity to the ObjectContext. However after calling Attach() the EntityState of this entity is still “Unchanged”, thus we need to change the EntityState of this entity to Added using the ObjectStateManager by calling context.ObjectStateManager.ChangeObjectState(entity, EntityState.Added).

Model Functions:
Model functions are functions defined using EntitySQL in the Conceptual Model (CSDL of the EDMX file). An Example of a Model Function (defined as a child element of the <Schema Namespace="EFRecipesModel"> element in the CSDL):

   1: <Function Name="GetInvoices" ReturnType="Collection(EFRecipesModel.Invoice)" >
   2: <Parameter Name="invoices" Type="Collection(EFRecipesModel.Invoice)">
   3: </Parameter>
   4: <DefiningExpression>
   5: Select VALUE i
   6: from invoices as i where i.Amount > 300M
   7: </DefiningExpression>
   8: </Function>

=========================================================
Note the distinction of Model Functions….these are defined in the Conceptual Model i.e. CSDL section of the EDMX file, whereas the DefiningQuery is defined in the SSDL section of the EDMX file and uses TSQL, if querying SQL Server, and return Entities from the Store layer.
An Example of a DefiningQuery is :

   1: <EntitySet Name="vOfficeAddresses"
   2:  EntityType="BreakAwayModel.Store.vOfficeAddresses" store:Type="Tables"
   3:  store:Schema="dbo" store:Name="vOfficeAddresses">
   4:    <DefiningQuery>
   5:      SELECT
   6:       [vOfficeAddresses].[FirstName] AS [FirstName],
   7:       [vOfficeAddresses].[LastName] AS [LastName],
   8:       [vOfficeAddresses].[addressID] AS [addressID]
   9:      FROM [dbo].[vOfficeAddresses] AS [vOfficeAddresses]
  10:    </DefiningQuery>
  11: </EntitySet>
=========================================================
One can also define Custom functions in the Store Layer (SSDL section of EDMX file) which are treated as Stored procedures whose return types can be scalar properties, ComplexTypes or Entities defined in the Conceptual layer. An example of a Custom function in SSDL (effectively seen as Sproc in the Model browser), defined as child element of the <Schema> element:
   1: <Function Name="MembersWithTheMostMessages" IsComposable="false">
   2: <CommandText>
   3: select m.*
   4: from chapter10.member m
   5: join
   6: (
   7: select distinct msg.MemberId
   8: from chapter10.message msg where datesent = @datesent
   9: ) temp on m.MemberId = temp.MemberId
  10: </CommandText>
  11: <Parameter Name="datesent" Type="date" />
  12: </Function>

Here the result of this custom Function is mapped to the Member Entity type in the CSDL.
=========================================================
QueryView is another type of query which is defined in the MSL i.e. mapping layer of the EDMX file. QueryView is written using ESQL, queries the Store layer Entities and returns Conceptual layer Entity. An Example of the Query view:

   1: <EntitySetMapping Name="WebOrders">
   2: <QueryView>
   3: select value
   4: EFRecipesModel.WebOrder(o.OrderId,
   5: o.CustomerName,o.OrderDate,o.IsDeleted,o.Amount)
   6: from EFRecipesModelStoreContainer.WebOrder as o
   7: where (o.OrderDate > datetime'2007-01-01 00:00') ||
   8: (o.OrderDate between cast('2005-01-01' as Edm.DateTime) and
   9: cast('2007-01-01' as Edm.DateTime) and !o.IsDeleted) ||
  10: (o.Amount > 800 and o.OrderDate &lt;
  11: cast('2005-01-01' as Edm.DateTime))
  12: </QueryView>
  13: </EntitySetMapping>

QueryViews come in handy when you need to filter by multiple criteria (as shown above), or you need to implement Table per Hierarchy inheritance when the foreign key defined in the derived tables is not the primary key of the derived table.


If you need to use one log4net file name for Messages having Level between WARN and ERROR and a different filename for Messages having Level between INFO AND DEBUG, then use the following log4net config:

   1: <log4net>
   2:     <appender name="RollingFileAppenderInfo" type="log4net.Appender.RollingFileAppender">
   3:       <file type="log4net.Util.PatternString" value="Results\%property{LogName}" />
   4:       <appendToFile value="true" />
   5:       <rollingStyle value="Size" />
   6:       <maxSizeRollBackups value="-1" />
   7:       <maximumFileSize value="10240KB" />
   8:       <staticLogFileName value="true" />
   9:       <countDirection value="1"/>
  10:       <threshold value="DEBUG"/>
  11:       <layout type="log4net.Layout.PatternLayout">
  12:         <conversionPattern value="%m%n" />
  13:       </layout>
  14:       <filter type="log4net.Filter.LevelRangeFilter">
  15:         <levelMin value="DEBUG" />
  16:         <levelMax value="INFO" />
  17:       </filter>
  18:       <filter class="log4net.Filter.DenyAllFilter"/>
  19:     </appender>
  20:  
  21:     <appender name="RollingFileAppenderError" type="log4net.Appender.RollingFileAppender">
  22:       <file type="log4net.Util.PatternString" value="%property{LogName}" />
  23:       <appendToFile value="true" />
  24:       <rollingStyle value="Size" />
  25:       <maxSizeRollBackups value="10" />
  26:       <maximumFileSize value="10240KB" />
  27:       <staticLogFileName value="true" />
  28:       <countDirection value="1"/>
  29:       <threshold value="WARN"/>
  30:       <layout type="log4net.Layout.PatternLayout">
  31:         <conversionPattern value="%d [%t] %-5p %c [%x] - %m%n" />
  32:       </layout>
  33:       <filter type="log4net.Filter.LevelRangeFilter">
  34:         <levelMin value="WARN" />
  35:         <levelMax value="ERROR" />
  36:       </filter>
  37:     </appender>
  38:  
  39:     <root>
  40:       <level value="DEBUG" />
  41:       <appender-ref ref="RollingFileAppenderInfo" />
  42:       <appender-ref ref="RollingFileAppenderError" />
  43:     </root>
  44:   </log4net>

Note here that I am using Dynamic logfile names so you need to call the following in your code to set up the Log4net File Names:

   1: GlobalContext.Properties["LogName"] = Log4netSetup.GetLog4NetLogFileName();
   2: XmlConfigurator.Configure(new FileInfo("CreateAssetCashFlows.exe.config"));

The Level’s in log4net are Off, FATAL, ERROR, WARN, INFO, DEBUG, ALL where OFF is the Highest Level and ALL is the Lowest Level.

Thus note that the following config is important :

   1: <threshold value="WARN"/>
   2: <filter type="log4net.Filter.LevelRangeFilter">
   3:   <levelMin value="WARN" />
   4:   <levelMax value="ERROR" />
   5: </filter>

The threshold parameter specifies that all Messages BELOW the Level WARN Will be ignored by this FileAppender. ( i.e. INFO, DEBUG & ALL Messages will be ignored)
The LevelRangeFilter states that Messages Between WARN & Error ONLY will be logged by this Appender.


Friday, June 18, 2010 #

1…Works like a charm:
   1: DECLARE @SearchStr nvarchar(100)
   2:  
   3: SET @SearchStr = 'SEARCH_KEYWORD'
   4:  
   5: CREATE TABLE #Results (ColumnName nvarchar(370), ColumnValue nvarchar(3630))
   6:  
   7: SET NOCOUNT ON
   8:  
   9: DECLARE @TableName nvarchar(256), @ColumnName nvarchar(128), @SearchStr2 nvarchar(110)
  10: SET  @TableName = ''
  11: SET @SearchStr2 = QUOTENAME('%' + @SearchStr + '%','''')
  12:  
  13: WHILE @TableName IS NOT NULL
  14: BEGIN
  15:     SET @ColumnName = ''
  16:     SET @TableName = 
  17:     (
  18:         SELECT MIN(QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME))
  19:         FROM     INFORMATION_SCHEMA.TABLES
  20:         WHERE         TABLE_TYPE = 'BASE TABLE'
  21:             AND    QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME) > @TableName
  22:             AND    OBJECTPROPERTY(
  23:                     OBJECT_ID(
  24:                         QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME)
  25:                          ), 'IsMSShipped'
  26:                            ) = 0
  27:     )
  28:  
  29:     WHILE (@TableName IS NOT NULL) AND (@ColumnName IS NOT NULL)
  30:     BEGIN
  31:         SET @ColumnName =
  32:         (
  33:             SELECT MIN(QUOTENAME(COLUMN_NAME))
  34:             FROM     INFORMATION_SCHEMA.COLUMNS
  35:             WHERE         TABLE_SCHEMA    = PARSENAME(@TableName, 2)
  36:                 AND    TABLE_NAME    = PARSENAME(@TableName, 1)
  37:                 AND    DATA_TYPE IN ('char', 'varchar', 'nchar', 'nvarchar')
  38:                 AND    QUOTENAME(COLUMN_NAME) > @ColumnName
  39:         )
  40:  
  41:         IF @ColumnName IS NOT NULL
  42:         BEGIN
  43:             INSERT INTO #Results
  44:             EXEC
  45:             (
  46:                 'SELECT ''' + @TableName + '.' + @ColumnName + ''', LEFT(' + @ColumnName + ', 3630) 
  47:                 FROM ' + @TableName + ' (NOLOCK) ' +
  48:                 ' WHERE ' + @ColumnName + ' LIKE ' + @SearchStr2
  49:             )
  50:         END
  51:     END    
  52: END
  53:  
  54: SELECT ColumnName, ColumnValue FROM #Results

2….Here is another TSQL code which helps in searching all stored procedures:

   1: SELECT Name FROM sys.procedures
   2: WHERE OBJECT_DEFINITION(OBJECT_ID) LIKE '%ProcessLog%'

OR use (this will search sprocs, udfs, triggers etc. (not just sprocs)):

   1: SELECT object_name(id) FROM syscomments where text like '%ProcessLog%'

3….. Here is another SQL which is helpful. If you have a lot of columns in a table and you need to find columns which are of a particular data type (e.g. datetime) then we can use this:

   1: SELECT * FROM SYSCOLUMNS WHERE Id = OBJECT_ID('geneva_security_extract') AND XTYPE = 61

. you pass in the name of the table to the OBJECT_ID function. Hope this helps