Friday, September 18, 2015

Intelli-sense for Javascript in Visual Studio

After you have enabled the Intelli-sense for Javascript in Visual Studio, the JQuery methods were still not available in your ".js" file, this is because you might have missed out the following directive:


    /// <reference path="jquery-1.7.js" />


Saturday, August 1, 2015

Failed to deserialize the object due to DLL version/name has changed

When you tried to deserialize the binary to an object but you encountered the following exception:

  BinaryFormatter.Deserialize “unable to find assembly”

Basically, it tells you that it cannot find the DLL by version + name. This is commonly issue when you change the DLL version number or move the class to another project/assembly. As a result, we need a way to tell the BinaryFormatter class what is the correct new "type" for the binary.

In the deserialization process, you need to add a line to use your custom binder:

using (MemoryStream memory = new MemoryStream(user_input))
{
    BinaryFormatter binary = new BinaryFormatter();

    //fix the deserialization error when the DLL version has been changed.
    binary.Binder = new PreMergeToMergedDeserializationBinder();

    // convert the binary to the list.
    this._data = binary.Deserialize(memory) as List<CUserDataItem>;
}

And then add the following class. I have enhanced this class and it is able to handle the generic list as well.

public sealed class PreMergeToMergedDeserializationBinder : System.Runtime.Serialization.SerializationBinder
{
    public override Type BindToType(string assemblyName, string typeName)
    {
        Type typeToDeserialize = null;

        // For each assemblyName/typeName that you want to deserialize to
        // a different type, set typeToDeserialize to the desired type.
        String exeAssembly = Assembly.GetExecutingAssembly().FullName;
      
        // The following line of code returns the type.

        // extract the 'old dll name/version'.
        string old_dll = typeName.ExtractString(',', ']');

        if (old_dll.IsNotEmpty())
        {
            // for generic list, we replace the dll name/version here.
            typeToDeserialize = Type.GetType(typeName.Replace(old_dll, exeAssembly.ToString()));
        }
        else
        {
            // for 1 single object, the 'typeName' is the class name.
            // We should return the type name with the new dll name/version.
            typeToDeserialize = Type.GetType(String.Format("{0}, {1}",
                                                typeName, exeAssembly));
        }

        System.Diagnostics.Debug.Assert(typeToDeserialize != null);

        return typeToDeserialize;
    }
}

I have an string class extension which helps to extract partial string:

public static string ExtractString(this string s,
    char start_char,
    char end_char)
{
    int i = s.IndexOf(start_char);
    if (i >= 0)
    {
        //16.Nov.2011-lhw-the 'end_char' should be search after the 'start_char'.
        int i2 = s.IndexOf(end_char,
                           i + 1);      //16.Nov.2011-lhw-missing the start pos!!

        string tmp = s.Substring(i + 1,
                                 i2 - i - 1);

        return tmp;
    }
    else
    {
        return string.Empty;
    }
}

Reference:
http://stackoverflow.com/questions/5170333/binaryformatter-deserialize-unable-to-find-assembly-after-ilmerge

Thursday, July 2, 2015

Routing to ASHX


Here is the piece of code that I found in CodeProject.com. By adding this extention method, you will be able to route the request to ASHX:

namespace System.Web.Routing
{
    public class HttpHandlerRoute : IRouteHandler
    {
        private String _virtualPath = null;
        private IHttpHandler _handler = null;

        public HttpHandlerRoute(String virtualPath)
        {
            _virtualPath = virtualPath;
        }

        public HttpHandlerRoute(IHttpHandler handler)
        {
            _handler = handler;
        }

        public IHttpHandler GetHttpHandler(RequestContext requestContext)
        {
            IHttpHandler result;
            if (_handler == null)
            {
                result = (IHttpHandler)System.Web.Compilation.BuildManager.CreateInstanceFromVirtualPath(_virtualPath, typeof(IHttpHandler));
            }
            else
            {
                result = _handler;
            }
            return result;
        }
    }

    public static class RoutingExtensions
    {
        public static void MapHttpHandlerRoute(this RouteCollection routes, string routeName, string routeUrl, string physicalFile, RouteValueDictionary defaults = null, RouteValueDictionary constraints = null)
        {
            var route = new Route(routeUrl, defaults, constraints, new HttpHandlerRoute(physicalFile));
            RouteTable.Routes.Add(routeName, route);
        }

        public static void MapHttpHandlerRoute(this RouteCollection routes, string routeName, string routeUrl, IHttpHandler handler, RouteValueDictionary defaults = null, RouteValueDictionary constraints = null)
        {
            var route = new Route(routeUrl, defaults, constraints, new HttpHandlerRoute(handler));
            RouteTable.Routes.Add(routeName, route);
        }
    }
}

To access the routing data in ASHX, you need to do this:


            var o = context.Request.RequestContext.RouteData.Values["id"];
            if (o != null)
            {
                q = o.ToString();
            }

Reference:
http://www.codeproject.com/Tips/272258/ASP-net-HttpHandler-Routing-Support

Posting data in JSON format to the ASP.NET website using WinForm

Previously, we have shown how to post JSON data using JQuery to ASP.NET.

  http://laucsharp.blogspot.com/2013/03/posting-data-in-json-format-to-aspnet.html

Now, we are going to post JSON data using WinForm:

This is our business object which will reside at the server and client.

    public class Class1
    {
        public string code { get; set; }
        public string name { get; set; }

        public override string ToString()
        {
            return string.Format("code={0}, name={1}",
                this.code,
                this.name);
        }
    }

In the WinForm client program, when the user hit Button1 after keyed in the client code and name, the data will be submitted to the server:

        private void button1_Click(object sender, EventArgs e)
        {
            // store the user input into the business object.
            Class1 data = new Class1();
            data.code = this.client_code.Text;
            data.name = this.client_name.Text;

            // convert it into json format.
            JavaScriptSerializer js = new JavaScriptSerializer();
            string json_data = js.Serialize(data);

            // create the web request.
            HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create("http://localhost:57655/dataGateway.ashx");
            request.ContentType = "application/json;";           
            request.Method = "POST";

            // write the json data into the request stream.
            using (StreamWriter writer = new StreamWriter(request.GetRequestStream()))
            {
                writer.Write(json_data);
            }

            // get the server response.
            using (WebResponse response = request.GetResponse())
            {
                // read the server response.
                Stream response_stream = response.GetResponseStream();
                using (StreamReader r = new StreamReader(response_stream))
                {
                    // do what ever you want with the response.
                    this.label5.Text = r.ReadToEnd();
                }
            }           
        }

Finally, at the server side, we add a Generic Handler (dataGateway.ashx) and it looks like this:

<%@ WebHandler Language="C#" Class="dataGateway" %>

using System;
using System.Web;
using System.IO;
using System.Web.Script.Serialization;

public class dataGateway : IHttpHandler
{
    public void ProcessRequest(HttpContext context)
    {
        context.Response.ContentType = "text/plain";

        string s;
       
        // get the contents from the request stream
        Stream stream = context.Request.InputStream;
        using (StreamReader r = new StreamReader(stream))
        {
            s = r.ReadToEnd();
        }

        // ensure that the content is not empty.
        if (string.IsNullOrEmpty(s) || s.Length == 0)
        {
            context.Response.Write("'data' cannot be blank");
            return;
        }

        // convert it from json format to our business object
        JavaScriptSerializer js = new JavaScriptSerializer();
        Class1 obj = js.Deserialize<Class1>(s);

        // do whatever you want
        context.Cache["data"] = obj;

        // returns the response code/status to the caller.
        context.Response.Write("ok. received the data =>" + s);
    }

    public bool IsReusable { get { return false; } }
}

Next, sending compressed data in WinForm:

    http://laucsharp.blogspot.my/2018/04/posting-compressed-data-in-json-format.html

Thursday, June 18, 2015

Excluding folders upon publishing the website

In VS2013, after you have setup the "publish" (right click on the website and choose Publish Web Site), a new configuration file (website.publishproj) will be added to the project.

To exclude the folders, you have to open this file and add the following section with the "project" section:

  <ItemGroup>
    <ExcludeFromPackageFolders Include="log;temp;">
      <FromTarget>Remove temp folders</FromTarget>
    </ExcludeFromPackageFolders>
  </ItemGroup>

In the "Include" attribute, it contains the folder to be removed when publishing the website. The above example excluding "log" and "temp" folders.


Sunday, June 14, 2015

Asp.net WebForm + Routing

To add the routing support in the WebForm, you need to add "System.Web.Routing" reference to your website.

Then, in the global.asax file, add the following codes:

void Application_Start(object sender, EventArgs e)
    {
        // Code that runs on application startup
        RegisterRoute(System.Web.Routing.RouteTable.Routes);
    }
   
    void RegisterRoute(System.Web.Routing.RouteCollection r)
    {
        // shows all customer
        r.MapPageRoute("allcust",
                        "customer",
                        "~/customer.aspx");
       
        // shows 1 customer profile
        r.MapPageRoute("cust",
                        "customer/{code}",
                        "~/customer.aspx");

        // shows the doc for the customer
        r.MapPageRoute("cust_doc",
                        "customer/{code}/{doc_no}",
                        "~/customer.aspx");

        // this allows any sub-level of parameters and the page requires to parse 'Page.RouteData.Values["queryvalues"]' (only 1 value).
        // The caller can call this route by the following url:
        //      /cust
        //      /cust/a001
        //      /cust/a001/inv123456
        //
        r.MapPageRoute("cust_query",
                        "cust/{*queryvalues}",
                        "~/customer.aspx");
       
    }

Finally, add all the aspx page that you need to display the information. In our example, we have only one page that is customer.aspx. You can get the parameter values in "Page.RouteData". Note: the last route that has been setup in the above was not shown in the following codes.

    protected void Page_Load(object sender, EventArgs e)
    {
        if (this.RouteData.Values.Count == 0)
        {
            this.lbl1.Text = "cust list";
        }
        else
        {
            if (this.RouteData.Values.Count == 1)
            {
                this.lbl1.Text = "customer => " + this.RouteData.Values["code"];
            }
            else
            {
                this.lbl1.Text = "customer => " + this.RouteData.Values["code"]
                    +",doc_no=" + this.RouteData.Values["doc_no"];
            }

            foreach (var item in this.RouteData.Values.Keys)
            {
                System.Diagnostics.Debug.WriteLine("param=" + item
                     + ",value=" + this.RouteData.Values[item]);
            }
        }
    }

If you need to set the navigate URL in the hyperlink control, this can be done easily as shown below:

    protected void Page_Load(object sender, EventArgs e)
    {
        // manually setup the URL based on the parameters.
        this.all_cust_link.NavigateUrl = RouteTable.Routes.GetVirtualPath(null, "allcust", null).VirtualPath;

        RouteValueDictionary d;
        d = new RouteValueDictionary();
        d.Add("code", "a001");

        this.one_cust_link.NavigateUrl = RouteTable.Routes.GetVirtualPath(null, "cust", d).VirtualPath;

        d = new RouteValueDictionary();
        d.Add("code", "a001");
        d.Add("doc_no", "inv123456");
        this.one_doc_link.NavigateUrl = RouteTable.Routes.GetVirtualPath(null, "cust_doc", d).VirtualPath;

    }


Thursday, April 23, 2015

ASP.NET UpdatePanel is not working in Google Chrome

I received a complaint from one of my user who said that the data grid not refreshing properly in Google Chrome.

Guess what..? I turned on the developer console in Chrome and found out that there is an error in loading some java script. After some research, I found the script below that fixed the problem:

Sys.Browser.WebKit = {};
if (navigator.userAgent.indexOf('WebKit/') > -1) {
            Sys.Browser.agent = Sys.Browser.WebKit;
            Sys.Browser.version = parseFloat(navigator.userAgent.match(/WebKit\/(\d+(\.\d+)?)/)[1]);
            Sys.Browser.name = 'WebKit';
}