Monday, 30 January 2012

Abstract Factory vs Factory

There are numerous post out there to explain the differences - i just wanted to add on

Factory - encapsulates the logic of creating a concrete type
Abstract Factory - encapsulates grouping of related factories.

I always start with Factory pattern first to decouple the creation logic from client.
So when will we go for Abstract Factory - as soon as your factory method violates Open/Closed principle. If your Factory method contains lots of 'if/else' or 'switch' statements, then it is time to move onto Abstract Factory. Please refer this article.

Also DBProviderFactory is another example of AF pattern. SqlClientFactory, OracleClientFactory, OleDbFactory are all grouped under DBProviderFactory.

http://en.wikipedia.org/wiki/Abstract_factory_pattern
http://en.wikipedia.org/wiki/Factory_object
http://msdn.microsoft.com/en-us/library/dd0w4a2z%28v=vs.80%29.aspx


Tuesday, 24 January 2012

Modifying Web.Config at run time

Sample code to update an app setting in web.config file at run time. I assume the user have physical path of the web.config, instead of virtual directory.

private static void ChangeAppSettting(string oldValue, string newValue)
{
            string appSettingName = "your app setting name";
            string configFilePath = "Your web.config path";
            Configuration configuration = OpenConfigFile(configFilePath );

            AppSettingsSection appSettings = configuration.AppSettings;

            if (appSettings != null && appSettings.Settings[appSettingName] != null)
            {
                appSettings.Settings[AppSetting].Value = newValue;
                configuration.Save();
            }
        }

        private static Configuration OpenConfigFile(string configPath)
        {
            FileInfo configFile = new FileInfo(configPath);
            VirtualDirectoryMapping virtualDirectoryMapping = new VirtualDirectoryMapping(configFile.DirectoryName, true, configFile.Name);
            var webConfigFileMap = new WebConfigurationFileMap();
            webConfigFileMap.VirtualDirectories.Add("/", virtualDirectoryMapping);
            return WebConfigurationManager.OpenMappedWebConfiguration(webConfigFileMap, "/");
        }

Tuesday, 17 January 2012

Useful IEnumerable Extensions

    ///

    /// Extension methods for IEnumerable
    ///

    public static class IEnumerableExtensions
    {
        ///
        /// Splits a list into list of buckets
        ///

        /// Type
        /// values
        /// Bucket size
        /// List of buckets
        public static IEnumerable> Split(this IEnumerable values, int chunkSize)
        {
            if (chunkSize <= 0)
            {
                throw new ArgumentException("chunkSize should be greater than zero");
            }

            if (values.IsNullOrEmpty())
            {
                throw new ArgumentException("value is either empty or null to Split");
            }

            while (values.Any())
            {
                yield return values.Take(chunkSize);
                values = values.Skip(chunkSize);
            }
        }

        ///
        /// Converts IEnumerable intp CSV
        ///

        /// Type
        /// values
        /// CSV
        public static String ToCSV(this IEnumerable values)
        {
            const string comma = ",";

            if (values.IsNullOrEmpty())
            {
                throw new ArgumentException("value is either empty or null");
            }

            return String.Join(comma, values.ToStrings().ToArray());
        }

        ///
        /// Converts IEnumerable<T> to IEnumerable<String>
        ///

        /// Type
        /// values
        /// IEnumerable<String>
        public static IEnumerable ToStrings(this IEnumerable values)
        {
            if (values.IsNullOrEmpty())
            {
                throw new ArgumentException("value is either empty or null");
            }

            foreach(var value in values)
            {
                yield return value.ToString();
            }
        }

        ///
        /// checks if the list contains any elements
        ///

        /// Type
        /// values
        /// true if not null and contains atleast one element, else false
        public static bool IsNullOrEmpty(this IEnumerable values)
        {
            if (values.IsNull() || values.Count() == 0)
            {
                return true;
            }

            return false;
        }
    }

Convert byte array to Image and vice versa

///


        /// Converts image into byte array
        ///

        ///
image
        ///
image format
        /// byte array
        public static byte[] ToByteArray(this Image data, ImageFormat format)
        {
            if (data.IsNull())
            {
                return null;
            }

            using (MemoryStream stream = new MemoryStream())
            {
                data.Save(stream, format);

                return stream.ToArray();
            }
        }

        ///

        /// Converts byte array into Image
        ///

        ///
image in form of byte array
        /// image
        public static Image ToImage(this byte[] data)
        {
            if (data.IsNullOrEmpty())
            {
                return null;
            }

            using (MemoryStream stream = new MemoryStream(data))
            {
                return Image.FromStream(stream);
            }
        }

Monday, 9 January 2012

error LGHT0132: The assembly file 'somedll.dll' appears to be invalid. Please ensure this is a valid assembly file and that the user has the appropriate access rights to this file.

When we try to build a wix project that refers an C++ dll, we may face below error

error LGHT0132: The assembly file 'somedll.dll' appears to be invalid.  Please ensure this is a valid assembly file and that the user has the appropriate access rights to this file.

It is strange cos it happens only in few machines. Following below steps might resolve the error

1. Open your *.wixproj file for editing.
2. Add <SuppressAssemblies>True<SuppressAssemblies> under a 'PropertyGroup' that has relevant 'Light' settings.


example:

  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
   
<OutputPath>bin\$(Configuration)\</OutputPath>
    <IntermediateOutputPath>obj\$(Configuration)\</IntermediateOutputPath>
    <WixVariables>BannerBitmap=..\..\Branding\TrustDigital\Installer\topimage.bmp;WixUILicenseRtf=..\..\Branding\TrustDigital\Installer\terms-of-use.rtf;WixUIDialogBmp=..\..\Branding\TrustDigital\Installer\leftsideimage.bmp</WixVariables>
  </PropertyGroup>





   I identified above as my relevant PropertyGroup becauase it contains 'WixVariables'(LIGHT related task), so i just need to insert <SuppressAssemblies>True<SuppressAssemblies> into this PropertyGroup.

Wednesday, 4 January 2012

2012

Finally 2011 is over, being said that it is not BAD for me. There are so many firsts - Birthday celebration with my wife, Anniversary, Europe trip and loss of wealth. Finally i quit TESCO(great employer though - just felt it is the time) and joined McAfee. Feeling good @ McAfee until now, these guys good at rewarding talents, provides good work environment and more importantly office is very closer to my apartment.

Personally it is a mixed feelings, though i have sustained tough times till now.

I don't have much expectations in 2012, just continue the good work and keep up good health.

And i managed to publish 50 articles :D

Custom(!!!) Basic Authentication

How often we think about using BASIC authentication only to figure out that it is hardwired to windows accounts? So what we have Custom Basic authentication using httpmodules. Excellent article here

One more compelling reason to go for Custom BASIC authentication, it is not tied to  UTF-8(uses ISO-8859-1), hence passing non 8-bit characters doesn't work at all.
http://stackoverflow.com/questions/702629/utf-8-characters-mangled-in-http-basic-auth-username/703341#703341
http://stackoverflow.com/questions/7242316/what-encoding-should-i-use-for-http-basic-authentication
http://greenbytes.de/tech/webdav/draft-reschke-basicauth-enc-latest.html
http://tools.ietf.org/html/rfc2617#section-2

Console client for a WCF Restful service protected with BASIC authentication(windows credential)

Please refer my earlier post for REST service details, below is an sample code to pass on windows credentials while calling WCF REST service(in IIS - Anonymous access is disabled and BASIC is enabled)

static void Main(string[] args)
        {
            Uri baseAddress = new Uri("http://localhost:8080/SimpleService");

            try
            {
                WebHttpBinding binding = new WebHttpBinding();

                binding.Security.Mode = WebHttpSecurityMode.TransportCredentialOnly;
                binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;

                WebChannelFactory cf = new WebChannelFactory(binding, baseAddress);
       
                //If Default domain is not added in IIS, provide it below - else not needed
                cf.Credentials.UserName.UserName = "user";
                cf.Credentials.UserName.Password = "password";

                SimpleInterface channel = cf.CreateChannel();
               
                Console.WriteLine("Reply Hi : {0}", channel.ReplyHi("Hello, world"));
                Console.WriteLine("Reply Hii : {0}",channel.ReplyHii("Hello, world"));
             }
            catch (CommunicationException ex)
            {
                Console.WriteLine("An exception occurred: " + ex.Message);
            }
        }

WCF Absolute Vs Relative address

After long break, i started working on WCF services and i struck with a problem when i hosted my service in IIS. I figured out that i have given an absolute end point address, which is wrong. So i figured out below in MSDN

'When hosting with IIS, you do not manage the ServiceHost instance yourself. The base address is always the address specified in the .svc file for the service when hosting in IIS. So you must use relative endpoint addresses for IIS-hosted service endpoints. Supplying a fully-qualified endpoint address can lead to errors in the deployment of the service. For more information, see Deploying an Internet Information Services-Hosted WCF Service."

So with following config
       
<services>
   <service name="RestService.SimpleService">
        <endpoint address="/Sample" binding="webHttpBinding"
                  contract="RestService.SimpleInterface" behaviorConfiguration="webby"
                   bindingConfiguration="secure"/>
     </service>
</services>

i hosted my WCF(REST) as 'SimpleRestService' application, so i need to use http://localhost/SimpleRestService/yoursvcfilename.svc/Sample/youroperationname

Issues while hosting Restful WCF services in IIS

When i hosted my Hello World WCF Restful services, i faced below issue

The requested content appears to be script and will not be served by the static file handler.

My application is using 'DefaultAppPool', For reasons unknown to me, running the below did work. 

c:\Windows\Microsoft.NET\Framework\v4.0.30319\aspnet_regiis.exe -i

But soon after this i ran into below issue

"Could not load type 'System.ServiceModel.Activation.HttpModule'"

For reasons unknown to me, running the below did work :(.   

c:\Windows\Microsoft.NET\Framework\v4.0.30319\aspnet_regiis.exe /iru

http://forums.asp.net/t/1432329.aspx/1 

http://www.fredmastro.com/post/HTTP-Error-40417-Not-Found-e28093-Using-WCF-SVC-Service.aspx 

http://support.microsoft.com/kb/2015129

Tuesday, 3 January 2012

POST vs PUT

This is just for my reference - which i read from articles

URI is noun and Methods are verbs
noun - refers some thing/verbs-actions

So PUT is used for CREATE/UPDATE a particular resource like
http://www.expensereports.com/sales/12345
in above example we either try to create a new sales report '12345' or updating it.

POST is again used for CREATE/UPDATE, but PUT might be a better option if we know what we are trying to update or create(hope we got it:)). Because POST is like handing over the request to a handler or manager who works on it.

So: To save an existing user, or one where the client generates the id and it's been verified that the id is unique:
PUT /user/12345 HTTP/1.1  <-- create the user providing the id 12345
Host: mydomain.com

GET /user/12345 HTTP/1.1  <-- return that user
Host: mydomain.com
Otherwise, use POST to initially create the object, and PUT to update the object:
POST /user HTTP/1.1   <--- create the user, server returns 12345
Host: mydomain.com

PUT /user/12345 HTTP/1.1  <--- update the user
Host: mydomain.com

Restful WCF services hosted in Console Application

Sorry - No descriptions, i am bored to death, hence only the code.

 namespace SimpleConsoleWCFHost
{
    [ServiceContract]
    public interface SimpleInterface
    {
        ///

        /// POST, bare body message - http://localhost:8080/SimpleService/SayHi/Suresh
        /// Content-Type: text/html
        ///

        ///
        [OperationContract]
        [WebInvoke(Method="POST", BodyStyle = WebMessageBodyStyle.Bare,
                UriTemplate="SayHi/{name}")]
        void SayHi(string name);

        ///
        /// GET, http://localhost:8080/SimpleService/ReplyHi/Suresh
        /// Content-Type: text/html
        ///

        ///
        ///
        [OperationContract]
        [WebInvoke(Method = "GET", BodyStyle = WebMessageBodyStyle.Bare,
                UriTemplate = "ReplyHi/{name}")]
        string ReplyHi(string name);

        ///
        /// GET, http://localhost:8080/SimpleService/ReplyHii?name=Suresh
        /// Content-Type: text/html
        ///

        ///
        ///
        [OperationContract]
        [WebGet]
        string ReplyHii(string name);

        ///
        /// GET, http://localhost:8080/SimpleService/ReplyByJson?name=Suresh
        /// Content-Type: text/json
        ///

        ///
        ///
        [OperationContract]
        [WebGet(ResponseFormat=WebMessageFormat.Json)]
        SimpleData ReplyByJson(string name);

        ///
        /// GET, http://localhost:8080/SimpleService/ReplyByXml?name=Suresh
        /// Content-Type: application/xml
        ///

        ///
        ///
        [OperationContract]
        [WebGet(ResponseFormat = WebMessageFormat.Xml)]
        SimpleData ReplyByXml(string name);

        ///
        /// POST, http://localhost:8080/SimpleService/ConverseUsingJson
        /// Content-Type: text/json
        /// {"Body":"Comment received at 03-01-2012 10:13:55","Header":"Welcome to JSON - Suresh"}
        ///

        ///
        ///
        [OperationContract]
        [WebInvoke(UriTemplate = "ConverseUsingJson", Method = "POST",
            RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
        SimpleData ConverseUsingJson(SimpleData data);

        ///
        /// POST, http://localhost:8080/SimpleService/ConverseUsingXml
        /// Content-Type: application/xml
        /// colin
        /// http://www.britishdeveloper.co.uk/2011/01/how-to-post-rest-fiddler.html
        ///

        ///
        ///
        [OperationContract]
        [WebInvoke(UriTemplate = "ConverseUsingXml", Method = "POST",
            RequestFormat = WebMessageFormat.Xml, ResponseFormat = WebMessageFormat.Xml)]
        SimpleData ConverseUsingXml(SimpleData data);
    }

    [DataContract(Namespace = "")]
    public class SimpleData
    {
        [DataMember]
        public string Header { get; set; }

        [DataMember]
        public string Body { get; set; }
    }

    public class SimpleService : SimpleInterface
    {
        public void SayHi(string name)
        {
            Console.WriteLine("Hi " + name);
        }

        public string ReplyHi(string name)
        {
            return "Hi " + name;
        }

        public string ReplyHii(string name)
        {
            return "Hii " + name;
        }

        public SimpleData ReplyByJson(string name)
        {
            return new SimpleData
            {
                Header = "Welcome to JSON - " + name,
                Body = "Comment received at " + DateTime.UtcNow.ToString()
            };
        }

        public SimpleData ReplyByXml(string name)
        {
            return new SimpleData
            {
                Header = "Welcome to XML - " + name,
                Body = "Comment received at " + DateTime.UtcNow.ToString()
            };
        }

        public SimpleData ConverseUsingJson(SimpleData value)
        {
            value.Header = "JSON Conversation";

            return value;
        }

        public SimpleData ConverseUsingXml(SimpleData value)
        {
            value.Header = "XML Conversation";

            return value;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Uri baseAddress = new Uri("http://localhost:8080/");
            string serviceName = "SimpleService";

            using (WebServiceHost webHost = new WebServiceHost(typeof(SimpleService), baseAddress))
            {
                ServiceEndpoint sp = webHost.AddServiceEndpoint(typeof(SimpleInterface), new WebHttpBinding(), serviceName);
                //ServiceDebugBehavior sdb = webHost.Description.Behaviors.Find();
                //sdb.HttpHelpPageEnabled = false;

                webHost.Open();

                Console.WriteLine("Host Opened");
                Console.ReadLine();

                webHost.Close();

                Console.WriteLine("Host Closed");
            }
        }
    }
}


Some fiddler shots below