new { Name = ”Shay Jacoby” }

Maximum separation, minimum Dependencies, No Injections.
Javascript and Css files compressor

 I was looking for a tool to compress js+css files that i can integrate into project post build event or MSBUILD.

One of the popular tools is  Yui, It works  fine but requieres installed JVM on DEV machine and it's not simple to write a wrapper for it.

I tried also the JSMin, It does the job but works for js files only.

 The best solution that I found is the .NET version of Yahoo.Yui.Compressor.

I integrated the assembly into a console app. and wrote a method that:

1. Gets the js scripts + css folder names as parameters.

2. Finds all files that contains *.debug in name, ignores all other files.

3. Reads file content as string and minify it - returns as minified string.

4. Saves the minified string to file named *.min instead of *.debug.

 

My web project post build event code (Format: "path to console app exe" "js files folder" "css files folder" ):

"$(SolutionDir)Reference Assemblies\tools\ShopEngine.Tools.exe" "$(SolutionDir)Web\Scripts" "$(SolutionDir)Web\Style"

The console app code:

namespace ShopEngine.Tools

{

    #region Using directives

 

    using System;

    using System.IO;

    using Yahoo.Yui.Compressor;

 

    #endregion

 

    /// <summary>

    /// Js + Css Minifier, Assembly taken from:

    /// http://yuicompressor.codeplex.com/

    /// </summary>

    public static class Minifier

    {

        #region Constants

 

        /// <summary>

        /// Debug file

        /// </summary>

        private const string Debug = "debug";

 

        /// <summary>

        /// Minified file

        /// </summary>

        private const string Min = "min";

 

        #endregion Constants

 

        /// <summary>

        /// Main method.

        /// </summary>

        /// <param name="args">The arguments.</param>

        public static void Main(string[] args)

        {

            if (args.Length == 0)

            {

                Console.WriteLine("invalid arguments, no path was specified.");

                return;

            }

 

            var di = new DirectoryInfo(args[0]);

            var files = di.GetFiles(string.Format("*.{0}.js", Debug), SearchOption.AllDirectories);

            var i = 0;

            foreach (var fi in files)

            {

                i++;

                string src = fi.FullName.ToLower();

                string srcText = File.ReadAllText(src);

                string dst = src.Replace(Debug, Min);

 

                string dstText = !string.IsNullOrEmpty(srcText) ? JavaScriptCompressor.Compress(srcText, false) : string.Empty;

 

                using (var streamWriter = new StreamWriter(dst))

                {

                    streamWriter.Write(dstText);

                }

            }

 

            Console.WriteLine("{0} Js Files minified.", i);

 

            // Check for Css folder

            if (args.Length > 1)

            {

                di = new DirectoryInfo(args[1]);

                files = di.GetFiles(string.Format("*.{0}.css", Debug), SearchOption.AllDirectories);

                i = 0;

                foreach (var fi in files)

                {

                    i++;

                    string src = fi.FullName.ToLower();

                    string srcText = File.ReadAllText(src);

                    string dst = src.Replace(Debug, Min);

 

                    string dstText = !string.IsNullOrEmpty(srcText) ? CssCompressor.Compress(srcText) : string.Empty;

                    using (var streamWriter = new StreamWriter(dst))

                    {

                        streamWriter.Write(dstText);

                    }

                }

 

                Console.WriteLine("{0} Css Files minified.", i);

            }

        }

    }

}

 

 

Good luck!

 

Real world error hadnling in ASP.NET MVC RC2.

I would like to share with You my ASP.NET MVC Error Handling solution after reading this question in stackoverflow.com 

Goal:

To catch every error that occures on server include HttpExeptions like 404 (Page not found).

The ability to choose a specific View (error Template) for some errors and a generic View/Behaviour if nor specific has been specified.
Scenario 1:
anonymus user typed a wrong url.
Actions:
display a user friendly message like: "OOPS, The page is missing... back to home"
Log the error to .log file on server.
Send email to admin.

Senario 2:
same as scenario 1 but one difference : user is anonymus but his IP is from our company office.
Actions:
show the detailed error.

Let's see some code:

 

Add this method to Global.asax:

protected void Application_Error(object sender, EventArgs e)
{
 
   Exception exception = Server.GetLastError();
 
 // Log the exception.
 ILogger logger = Container.Resolve<ILogger>();
 logger.Error(exception);
 
 Response.Clear();
 
 
 HttpException httpException = exception as HttpException;
 RouteData routeData = new RouteData();
 routeData.Values.Add("controller", "Error");
 
 if (httpException == null)
 {
      routeData.Values.Add("action", "Index");
 }
 else //It's an Http Exception, Let's handle it.
 {
 
  switch (httpException.GetHttpCode())
  {
    case 404:
      // Page not found.
      routeData.Values.Add("action", "HttpError404");
      break;
     case 500:
     // Server error.
       routeData.Values.Add("action", "HttpError500");
       break;
       // Here you can handle Views to other error codes.
        // I choose a General error template  
        default:
        routeData.Values.Add("action", "General");
        break;
     }
  }
 
 // Pass exception details to the target error View.
 routeData.Values.Add("error", exception);
 
 // Clear the error on server.
 Server.ClearError();
 
// Call target Controller and pass the routeData.
 IController errorController = new ErrorController();
 errorController.Execute(new RequestContext(
new HttpContextWrapper(Context), routeData));
 
}


Created a new controller called ErrorController:
You can specify some more behaviors to another eception types, I breated a view just for error: 404, 500.

 

    public ActionResult HttpError404(string error)
        {
            ViewData["Title"] = "Sorry, an error occurred while processing your request. (404)";
            ViewData["Description"] = error;
            return View("Index");
        }
 
        public ActionResult HttpError500(string error)
        {
            ViewData["Title"] = "Sorry, an error occurred while processing your request. (500)";
            ViewData["Description"] = error;
            return View("Index");
        }
 
 
        public ActionResult General(string error)
        {
            ViewData["Title"] = "Sorry, an error occurred while processing your request.";
            ViewData["Description"] = error;
            return View("Index");
        }

 

I attached an example project to this post.

 

MVC Framework RC1 - Moq vs. TypeMock Isolator Controller test

A new version of MVC Framework is just released and has some cool improvements:

The Views have no ".cs" (code behind like) files.

You could generate CRUD Views from VS.

HTML Form fields could be Type Safe, You could Bind class property to form field.

The Controller action behavior is very testability, example:

The Moq example from ScottGu's post:

 

[TestMethod]

   public void Display_Message_Authenticated()

   {

      // Arrange

      HomeController controller = new HomeController();

 

      Mock<ControllerContext> mockControllerContext = new Mock<ControllerContext>();

      mockControllerContext.Setup(c => c.HttpContext.Request.IsAuthenticated).Returns(true);

      mockControllerContext.Setup(c => c.HttpContext.User.Identity.Name).Returns("test");

      controller.ControllerContext = mockControllerContext.Object;

 

      // Act

      ViewResult result = controller.DisplayMessage() as ViewResult;

 

      // Assert

      Assert.IsNotNull("DisplayMessage() should have returned a ViewResult.");

 

 

      ViewDataDictionary viewData = result.ViewData;

      Assert.AreEqual("Hello test", viewData["Message"], "Message incorrect");

    }

 

Here's a test I wrote using TypeMock Isolator:

 

[TestMethod]

[Isolated]

public void Display_Message_Authenticated_using_TypeMock()

{

  // Arrange

  HomeController controller = new HomeController();

 

  ControllerContext mockControllerContext = Isolate.Fake.Instance<ControllerContext>();

  Isolate.WhenCalled(() => mockControllerContext.RequestContext.HttpContext.

Request.IsAuthenticated).WillReturn(true);

 

  Isolate.WhenCalled(() => mockControllerContext.RequestContext.HttpContext.

User.Identity.Name).WillReturn("test");

  controller.ControllerContext = mockControllerContext;

 

 

   // With TypeMock You can Mock HttpContext directley without mocking the ControllerContext:

   Isolate.WhenCalled(() => HttpContext.Current.Request

.IsAuthenticated).WillReturn(true);

 

   // Act

   ViewResult result = controller.DisplayMessage() as ViewResult;

   Isolate.WhenCalled(() => mockControllerContext.RequestContext

.HttpContext.Request.IsAuthenticated).WillReturn(true);

  // Assert

  Assert.IsNotNull("DisplayMessage() should have returned a ViewResult.");

 

 

 

    ViewDataDictionary viewData = result.ViewData;

    Assert.AreEqual("Hello test", viewData["Message"], "Message incorrect");

}

 

I attached both test methods as attachement to this post.

 

Cool!

Typemock Isolator 5.2 release

Hi, There's a new release of Typemock Isolator 5

This tool is excellent and helps to improve your unit tests.

 

 

 


Programming Visual Basic applications?

Typemock have released a new version of their unit testing tool, Typemock Isolator 5.2.
This version includes a new friendly VB.NET API which makes Isolator the best Isolation tool for unit testing A Visual Basic (VB) .NET application.
Isolator now allows unit testing in VB or C# for many ‘hard to test’ technologies such as SharePoint, ASP.NET MVC, partial support for Silverlight, WPF, LINQ, WF, Entity Framework, WCF unit testing and more.

Note that the first 25 bloggers who blog this text in their blog and tell us about it, will get a Free Full Isolator license (C#, VB, and Sharepoint included - worth $139 !!!). If you post this in a VB.NET dedicated blog, you'll get a license automatically (even if more than 25 submit) during the first week of this announcement.

Go ahead, click the following link for more information on how to get your free license.

 

Mvc custom ActionFilterAttribute for ajax requests caching

One of the most important performance improvements issues on Web Applications is caching AJAX calls on client browser.

Faster page responses improve the client UI as well.

Since I read about this little hack of omar zabir that fixes a known .net framework Cache-Control header setting bug  I implement this solution on every project.

For Web Application I keep on using MVC Framework beta so a very elegant to implement ajax responses caching by creating a custom ActionFilterAttribute class.

Important: You can put in client side cache only Ajax "GET" requests.

the Code:

namespace Framework.Mvc.ActionFilters
{
 
    using System;
    using System.Reflection;
    using System.Web;
    using System.Web.Mvc;
 
    public class AjaxOutputCache : ActionFilterAttribute
    {
        /// <summary>
        /// Gets or sets the duration.
        /// </summary>
        /// <value>The duration.</value>
        public double Duration { get; set; }
 
        /// <summary>
        /// Called when [action executed].
        /// </summary>
        /// <param name="filterContext">The filter context.</param>
        public override void OnActionExecuted(ActionExecutedContext
 filterContext)
        {
            if (Duration <= 0) return;
            SetCache(Duration);
        }
 
 
        /// <summary>
        /// Sets cache header to client's browser.
        /// </summary>
        /// <param name="cacheDurationInMinutes" type="double">
Cache duration (in minutes).</param>
        private static void SetCache(double cacheDurationInMinutes)
        {
            TimeSpan duration = 
TimeSpan.FromMinutes(cacheDurationInMinutes);
            HttpCachePolicy cache = 
HttpContext.Current.Response.Cache;
            cache.SetCacheability(HttpCacheability.Public);
            cache.SetExpires(DateTime.Now.Add(duration));
            cache.SetMaxAge(duration);
            cache.AppendCacheExtension("must-revalidate, 
proxy-revalidate");
            FieldInfo maxAgeField = cache.GetType().GetField(
"_maxAge", BindingFlags.Instance | BindingFlags.NonPublic);
            maxAgeField.SetValue(cache, duration);
 
        }
 
    }
}

 Example usage:

 /// <summary>
 /// Find client data by specifies client id.
 /// </summary>
 /// <param name="id" type="string">client unique 
identifier.</param>
 /// <returns>results in json format.</returns>
 [AjaxOutputCache(Duration = 10)]
 public JsonResult Show(string id)
 {
   id = id.DecodeUrl();
   var item = _client.FindBy(id);
   return Json(item);
}

once this method is executed, it's results is cached by the client browser for 10 minutes (see the attribute: (Duration = 10)).

I checked the http protocol with fiddler on IE and firebug on FF and I saw that the the first request has status code 200 (OK) and takes about 3 seconds, the next request (with same parameter) take 2-3 milliseconds and not served by IIS at all.

 

I attched the class as attachment.
Good Luck.

Shay

Building a basic IoC

I used to work with the IoC libraries Unity Application Block, StructureMap which I found very good but I wanted a very basic one that keeps the services/repositories as singleton, no need to manage state/lifetime of objects..

I didn't use one of the libraries I mentioned above because I don't need most of their functionallity.

So... I wrote my basic IoC and would like to share it with You:

Step 1 - App.Config/Web.config

<configSections>

    <!--Add this line inside "configSections" -->

    <section name="ioc" type="Framework.IoC.MappingSectionHandler, Framework.IoC, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ce99303d14144e28"/>

</configSections>

 

Step 2 - Add object mapping table

 

add your mapping table after end of </configSections>:

 

Here's an example configuration from my current project:

   

<ioc>

     <!--Infrastracture components-->

     <!--<type name="Framework.Core.ILogger" mapTo="Framework.Logging.NLogLogger, Framework.Logging, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ce99303d14144e28"/>-->

     <type name="Framework.Core.ILogger" mapTo="Framework.Logging.Log4NetLogger, Framework.Logging, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ce99303d14144e28"/>

     <type name="Framework.Core.ICacheManager" mapTo="Framework.Caching.CacheManager, Framework.Caching, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ce99303d14144e28"/>

     <type name="Framework.Core.IEmail" mapTo="Framework.Messaging.Email, Framework.Messaging, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ce99303d14144e28"/>

     <type name="Framework.Core.IValidation" mapTo="MvcValidation.NHibernateValidation, MvcValidation, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ce99303d14144e28"/>

 

      <type name="Framework.IRepository.IArticleRepository" mapTo="Framework.NHibernateRepository.ArticleRepository, Framework.NHibernateRepository"/>

     <type name="Framework.IRepository.IContactRepository" mapTo="Framework.NHibernateRepository.ContactRepository, Framework.NHibernateRepository"/>

     <type name="Framework.IRepository.IEventRepository" mapTo="Framework.NHibernateRepository.EventRepository, Framework.NHibernateRepository"/>

     <type name="Framework.VR.IRepository.IClientRepository" mapTo="Framework.VR.NHibernateRepository.ClientRepository, Framework.VR.NHibernateRepository"/>

</ioc>

 

 

Step 3 - Create a new class library project, I called it "Framework.IoC".

 

Step 4 - Add a new class called "MappingSectionHandler.cs" and paste the following code into it:

 

 

namespace Framework.IoC

{

 

    #region Using directives

 

    using System.Configuration;

    using System.Collections.Generic;

    using System.Xml;

 

    #endregion

 

    public class MappingSectionHandler : IConfigurationSectionHandler

    {

 

        #region IConfigurationSectionHandler Members

 

 

        /// <summary>

        /// Iterate through all the child nodes of the XMLNode that

        /// was passed in and extract the information into a Dictionary.

        /// </summary>

        /// <param name="parent">Parent object.</param>

        /// <param name="configContext">Configuration context object.</param>

        /// <param name="section">The XML section we will iterate against</param>

        /// <returns>The created section handler object.</returns>

        public object Create(object parent, object configContext, XmlNode section)

        {

            var dictionary = new Dictionary<string, string>();

 

            foreach (XmlNode item in section.ChildNodes)

                if (item.NodeType != XmlNodeType.Comment)

                    dictionary[item.Attributes["name"].Value] = item.Attributes["mapTo"].Value;

 

            return dictionary;

        }

 

        #endregion

 

    }

}

 
 
Step 5 - Add a new class called "Container" and paste the following code into it:
 


 

namespace Framework.IoC

{

 

    #region Using directives

 

    using System;

    using System.Collections.Generic;

    using System.Configuration;

    using Properties;

 

    #endregion

 

    /// <summary>

    /// The IoC Container static class provides inversion of control and service lookup functionality.

    /// </summary>

    public static class Container

    {

        /// <summary>

        /// static readonly dictionary to store the instances.

        /// </summary>

        private static readonly IDictionary<string, object> factories = new Dictionary<string, object>();

 

        /// <summary>

        /// Configuration Section name

        /// </summary>

        private const string sectionName = "ioc";

 

        /// <summary>

        /// some object to lock when filling the dictionary to rnsure thread safety.

        /// </summary>

        private static readonly object iocLock = new object();

 

        /// <summary>

        /// resolve a component of the specified <typeparamref name="T"/> type.

        /// </summary>

        /// <typeparam name="T">The type of component to resolve or build.</typeparam>

        /// <returns>An instance of <typeparamref name="T"/>.</returns>

        public static T Resolve<T>() where T : class

        {

            T factory;

 

            var key = typeof(T).FullName;

            object factoryItem;

 

            // See if the factory is in the cache

            if (factories.TryGetValue(key, out factoryItem))

            {

                // It was there, so retrieve it from the cache.

                factory = factoryItem as T;

            }

            else

            {

                // not in dictionary, let's create the factory.

 

                // Get the entityMappingsConfiguration config section

                var dictionary = (Dictionary<string, string>)ConfigurationManager.GetSection(sectionName);

                string typeName;

                if (!dictionary.TryGetValue(key, out typeName))

                    throw new ArgumentOutOfRangeException(string.Format(Resources.key_not_found, key));

 

                // Get the type to be created using reflection

                var factoryType = Type.GetType(typeName);

 

                // if factoryType is null throw.

                if (factoryType == null)

                    throw new NullReferenceException(typeName);

 

                // Create the factory using reflection

                factory = Activator.CreateInstance(factoryType) as T;

 

 

                lock (iocLock)

                {

                    // Put the newly created factory in the cache

                    factories[key] = factory;

                }

            }

 

            // if null than throw Exception.

            if (factory == default(T))

                throw new Exception(string.Format(Resources.cannot_instanciate, key));

 

            return factory;

 

        }

 

 

    }

}

 
 
Step 6 - see some example usages:
 
basic usage:

var logger = IoC.Container.Resolve<ILogger>();

logger.Debug("Sample message");

 
 
 
example class:
 

public class Accounts

    {

 

        private IRepository _repository;

 

        public Accounts()

        {

            _repository = Container.Resolve<IRepository>();

        }

 

 

 

        public void Save()

        {

            var account = new Account(1, "test");

            _repository.Save(account);

        }

 

    }

 
------------------------------------------------------
 
I added the code as post attachement.
Good Luck.

 
Shay.
How to call Web/WCF Services without ScriptManager

Hi, 

I wrote a generic client-side javascript in order to simplify the work with Web/WCF Services.

Script Benefits (or Why do you need such a script...?):

1. If you use this script, You don't need to use ScriptManager or any form runat="server" in order to consume a Web/WCF Service. The unnesesery viewstate increase your page.

2. You can call a Web/WCF Service from any static HTML file.

3. Very light script (1.4 k) , the ScripyManager generated output scripts are much larger.

4. The must be some more good reasons to use it ( but it late and I'm tired).

I attached the Ajaxlib.js as attachment for download.

Enjoy it!


Here are 2 "real world" examples of the script usage:

 /*start method that calls a WCF service */

function GetZip(city, address, houseNum)

 

{

if (!IsEmpty(city) && !IsEmpty(address) && !IsEmpty(houseNum))

 

{

 

// Service url

var url = "ServiceModel/ZipService.svc/ZipSelectByAddress";

 

// Service params

var params = "city=" + escape(city);

 

params = params + "&address=" + escape(address);

params = params + "&houseNum=" + escape(houseNum);

 

//target Object, object that will be available in the callback method, e.g. "myDivID".

var targetObject = "txtsZip";AJAX.init("GET", url, onGetZipCompleted, params, targetObject)

 

}

 

}

 

 

 

//callback method to process results from xml http object

function onGetZipCompleted(responseText, targetObject)

 

{

var resInput = document.getElementById(targetObject);

 

// Eval JSON response into variable

var obj = eval('(' + responseText + ')');

 

var res = obj["d"];

if (res =='0')res = '00000';

 

resInput.value = res;

 

}

 

 

/*end of method that calls a WCF service*/

 

 Web Service example, i use the XML output option:

 

/* Web Service call */

function getFiles(id)

{

if (id > 0)

{

//Build url with params

var url = "/Services/FileManagerInfoService.asmx/GetFiles";

var params = "id=" + id;

AJAX.init("GET", url, onGetFilesCompleted, params, "divUploads", "XML");

}

}

function onGetFilesCompleted(res, targetObject){
document.getElementById(targetObject).innerHTML = res;
}

/* End of Web Service call */

 

  

/*--------start Ajaxlib.js-----------*/

 

/* Written by Shay Jacoby (s-online.co.il) */
AJAX = {
xmlHttp:'', 
targetObject:null,
outputFormat:'XML',
init : function(methodType, url, callback, params, targetObject, outputFormat){ 
AJAX.xmlHttp=AJAX.getXmlHttpObject();
 
if (AJAX.xmlHttp==null){
    alert ("Your browser does not support AJAX!");
    return;
} 
 
if (methodType=="GET" && params!=null){
    url = url + "?" + params;
}
 
if (outputFormat!=null)
    AJAX.outputFormat = outputFormat;
 
AJAX.targetObject = targetObject;
 
AJAX.xmlHttp.open(methodType,url,true);
 
if (methodType=="POST" && params!=null){
    if (outputFormat=="JSON"){
        AJAX.xmlHttp.setRequestHeader("Content-Type", "application/json; charset=utf-8");
        //Convert params to Json format
        params = AJAX.toJsonParams( params );
    }
    else {
        AJAX.xmlHttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
        AJAX.xmlHttp.setRequestHeader("Content-length", params.length);
        AJAX.xmlHttp.setRequestHeader("Connection", "close");
    }  
}
 
//not tested:
//AJAX.xmlHttp.setRequestHeader("Pragma", "no-cache");
//AJAX.xmlHttp.setRequestHeader("Cache-Control", "no-cache");
 
AJAX.xmlHttp.onreadystatechange=function(){AJAX.stateChanged(callback)};
 
AJAX.xmlHttp.send(params);
},
 
stateChanged : function(callback){
    // Returns the status of the request:
    // 0 uninitialized, 1 loading, 2 loaded, 3 interactive, 4 complete 
    if (AJAX.xmlHttp.readyState==4){
        //purposes we are only interested in OK (200) response.
        if (AJAX.xmlHttp.status == 200){
            switch(AJAX.outputFormat){
                case "JSON":
                    if (callback) callback(AJAX.xmlHttp.responseText, AJAX.targetObject);
                    break;
                case "XML":
                    if (callback) callback(AJAX.xmlHttp.responseXML, AJAX.targetObject);
                    break;
            }
        } 
        else {
            // there was a problem with the request, for example the response may 
            // be a 404 (Not Found) or 500 (Internal Server Error) response codes.
            alert('ERROR: ' + AJAX.xmlHttp.statusText + ' (' + AJAX.xmlHttp.status + ')');
            return;
        }
    }
},
 
//method: Convert parameters to Json Format e.g. {"param1":"param1Value", "param2":"param2Value"}
toJsonParams : function(qStr){
 
    if (qStr==null || qStr.length==0)
        return "{''}";
 
    var output = "{";
    var params = qStr.split("&");
    for (i=0;i<params.length;i++) {
        var prmArr = params[i].split("=");
        output += "\""  + prmArr[0] +  "\"";
        output += ":";
        output += "\""  + prmArr[1] +  "\",";
    }
     if (output.indexOf(',' > 0))
        output = output.slice(0, -1);
    output += "}";
    return output;
},
 
getXmlHttpObject : function(){
    AJAX.xmlHttp=null;
    try {
        // Firefox, Opera 8.0+, Safari, IE7
        AJAX.xmlHttp=new XMLHttpRequest();
    }
    catch (e){
        // Internet Explorer
        try{
            AJAX.xmlHttp=new ActiveXObject("Msxml2.XMLHTTP");
        }
        catch (e){
            AJAX.xmlHttp=new ActiveXObject("Microsoft.XMLHTTP");
        }
    }
    return AJAX.xmlHttp;
    }
}

 

 

 

/*--------End Ajaxlib.js-----------*/