DCSIMG
עמוד הבית| חבילות השירות שלנו| חומר חופשי| צור קשר
July 2009 - Posts - בלוג היועצים של מיקרוסופט ישראל

בלוג היועצים של מיקרוסופט ישראל

July 2009 - Posts

SQL - This time in other site

 

באתר (המצויין באופן כללי) sqlserver.co.il פורסם ראיון איתי. למי שמתעניין הלינק הוא http://www.sqlserver.co.il/?p=495

 

Velocity And Transactions

In this post, I will present a sample class that enables me to work with "Velocity" cache under a transaction scope of System.Transaction.

This class is very limited, but of course, you can take this sample and improve it / expand it for your needs.

This class support only "Put" method of "Velocity" "CacheData" class and only 2 of it overloads. It's also does not return the "DataCacheItemVersion", as the original "Velocity" "Put" method do.

The concept of this class is very simple, its act as Resource Manager who managed by a Transaction Manager (see: Enlisting Resources as Participants in a Transaction).
While initiate the class, the constructor get an instance of "Velocity" "DataCache", it's also enlist to the current transaction scope.  If no transaction scope will found, the class will throw an exception.

When the user call the "Put" method, all the data he sent to the method, stored in the class instance memory without "Put" it into the "Velocity" cache. The actual insertion is done in the "Prepare" phase of the transaction (the Transaction Manager is responsible for calling this method). That is the reason the class does not return the "DataCacheItemVersion" in the "Put" method.

Also, I have to handle the "Rollback" method. The class "remove' from Velocty cache, all the items that were inserted in this "session".

As a side effect, this class enable a "Bulk" insertion by execute a few "Put" action in a single transaction scope.

 I hope it will be helpful for you and I will glad to get your feedbacks. Tal 
using System;
using System.Transactions;
using Microsoft.Data.Caching;
using System.Collections.Generic;
 
namespace VelocityTools
{
    /// <summary>
    /// This class is a wrapper on Velocity CacheData that support transaction on "Put" actions.
    /// It's also enable a Bulk insertion by allow multiple "Put" actions in single transaction scope.
 
    /// When a user "Put" data into the cache, the data stored in the class instance. 
    /// Only when the transaction scope is completed, the data will be "Put" into the velocity cache.
    /// </summary>
    /// <typeparam name="TDataCache">A Velocity DataCache</typeparam>
    public class TransactionalDataCache <TDataCache>: IEnlistmentNotification where TDataCache:DataCache
    {
 
        /// <summary>
        /// Initiate the class.
        /// Exception will thrown if no transaction scope exist.
        /// </summary>
        /// <param name="dataCache">A Velocity DataCache</param>
        public TransactionalDataCache(TDataCache dataCache)
        {
            if (Transaction.Current == null)
                throw new Exception("No TransctionScope exist");
 
            Transaction.Current.EnlistVolatile(this, EnlistmentOptions.None);
 
            this.LocalCache = dataCache;
            this.CachedDataList = new List<ItemToCache>();
        }
 
        /// <summary>
        /// The velocity CacheData instance
        /// </summary>
        private TDataCache LocalCache { get; set; }
 
        /// <summary>
        /// This list hold all the data the the user want to cache.
        /// </summary>
        private List<ItemToCache> CachedDataList {get;set;}
 
 
        /// <summary>
        /// Adds or replaces an object in the cache.
        /// </summary>
        /// <param name="key">The unique value that is used to identify the object in the cache.</param>
        /// <param name="value">The object to add or replace.</param>
        public void Put(string key, object value)
        {
            this.Put(key, value, null);
        }
 
 
        /// <summary>
        /// Adds or replaces an object in the specified region.
        /// </summary>
        /// <param name="key">The unique value that is used to identify the object in the cache.</param>
        /// <param name="value">The object to add or replace.</param>
        /// <param name="region">The name of the region the object resides in.</param>
        public void Put(string key, object value, string region)
        {
            this.CachedDataList.Add(new ItemToCache() { Key = key, Value = value , Region = region });
        }
 
 
        #region IEnlistmentNotification Members
 
 
        public void InDoubt(Enlistment enlistment)
        {
            enlistment.Done();
        }
 
 
 
        public void Prepare(PreparingEnlistment preparingEnlistment)
        {
            try
            {
                ///try to "Put" the data into velocity cache.
                ///each item that is "Put" in the velocty cache, marked as "IsCached"=true.
                this.PutItemsToCache();
                preparingEnlistment.Prepared();
            }
            catch(Exception ex)
            {
                ///remove all the items that already "Put" in the Velocity cache.
                this.RemoveItemsFromCache();
                preparingEnlistment.ForceRollback(ex);
            }
        }
 
        public void Commit(Enlistment enlistment)
        {
            ///clear the current instance, 
            ///so if the user will try to work with this instance after commit or rollback, he will failed.
            this.ClearInstance();
 
            enlistment.Done();
        }
 
        public void Rollback(Enlistment enlistment)
        {
            ///remove all the items that already "Put" into Velocity cache.
            this.RemoveItemsFromCache();
 
            ///clear the current instance, 
            ///so if the user will try to work with this instance after commit or rollback, he will failed.
            this.ClearInstance();
 
            enlistment.Done();
        }
 
        #endregion
 
 
        /// <summary>
        /// "Put" all the items into the Velocity cache.
        /// Each item that successfully added, marked as "IsCached"=true
        /// </summary>
        private void PutItemsToCache()
        {
            foreach (var data in this.CachedDataList)
                this.Put(data);
        }
 
        /// <summary>
        /// "Put" an item into the Velocity cache.
        /// if the item successfully added, marked as "IsCached"=true
        /// </summary>
        /// <param name="data">An Item to "Put" into the velocty cache</param>
        private void Put(ItemToCache data)
        {
            if (data.Region == null)
                this.LocalCache.Put(data.Key, data.Value);
            else
                this.LocalCache.Put(data.Key, data.Value, data.Region);
 
            data.IsCached = true;
        }
 
 
        /// <summary>
        /// Remove all the items that marked as "IsCached" = true
        /// from the velocity cache.
        /// </summary>
        private void RemoveItemsFromCache()
        {
            foreach (var data in this.CachedDataList)
                if(data.IsCached)
                    this.Remove(data);
        }
 
        /// <summary>
        /// Remove an Item from the Velocity cache.
        /// </summary>
        /// <param name="data">An Item to remove from velocity cache</param>
        private void Remove(ItemToCache data)
        {
            if (data.Region == null)
                this.LocalCache.Remove(data.Key);
            else
                this.LocalCache.Remove(data.Key, data.Region);
        }
 
        /// <summary>
        ///clear the current instance, 
        ///so if the user will try to work with this instance after commit or rollback, he will failed.
        /// </summary>
        private void ClearInstance()
        {
            this.LocalCache = null;
            this.CachedDataList.Clear();
            this.CachedDataList = null;
        }
 
 
        /// <summary>
        /// This class represent data to cache.
        /// </summary>
        private class ItemToCache
        {
            public ItemToCache()
            {
                this.IsCached = false;
            }
 
            public string Key { get; set; }
            public string Region { get; set; }
            public object Value { get; set; }
            public bool IsCached { get; set; }
        }
    }
}

Exchange Web Service (EWS) and Versioning

Lately I introduced to a great API from the Exchange team, that simplify the working with the EWS.
If you are working with EWS, hurry up and take a look on this
API
.

When I started to play with this API, I noticed that I have no problem to create items and update them,
but if I tried to update an item that was created by the EWS (and not by the Managed API), I have got this exception:
"The EWS Id specified is in Exchange 2007 RTM format while your request was made in the Exchange2007_SP1 mode.
Please use the Exchange2007 SOAP version header in your request or remove it,
or use ConvertId method to convert Id from EwsLegacyId to EwsId format."

So, I searched information about this error and found this post (
http://calendarservermigration.blogspot.com/2008/05/meetings-created-in-ews-rtm-format-can.html
) that talk about the differences between item ID in Exchange 2007 RTM and Exchange 2007 SP1.
Shortly, this error thrown when you are trying to read/update an item that created with Exchange 2007 RTM EWS,
with EWS (or Managed API) of Exchange 2007 sp1.

Also, I read this
article
and I learned that I can set the EWS Managed API target version like that:
ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2007_SP1);

So, I did it.
And… still I have got the exception….

Since I created items by EWS of Exchange 2007 sp1 and tried to update those items with the Managed API (that I set its version to "Exchange2007_SP1") I should not get an error…

After some digging I found this
article that said that we can (and need) to set the EWS version, because its default version is "Exchange2007
".

So, if you will have this error you should set the version of the EWS Manged API:
ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2007_SP1);

And set the EWS version:
ExchangeServiceBinding esb = new ExchangeServiceBinding();
esb.RequestServerVersionValue = new RequestServerVersion();
esb.RequestServerVersionValue.Version = ExchangeVersionType.Exchange2007_SP1;


Good luck