Wednesday, March 19, 2014

.NET 4.0 Consume weblogic web service

Recently i have a project which need to consume a weblogic web service using .NET framework 4.0. At first i think it were similar to calling other java web service, which adding service reference and then all is done, but when i am working on it, i soon find that there is a problem on the authentication part.

I have the sample call which write in Java and the code to do the authentication is like following


        BindingProvider bindingProvider = (BindingProvider)soapService;
        bindingProvider.getRequestContext().put(BindingProvider.USERNAME_PROPERTY, username);
        bindingProvider.getRequestContext().put(BindingProvider.PASSWORD_PROPERTY, password);


Poor that in .NET framework 4.0, there seems no similar stuff with that. So what it actually doing on these few lines? In this forum, i find a solution at the bottom which overrides the service client to add the header, but it is for .NET 2.0 webservice
http://bytes.com/topic/net/answers/427818-calling-web-service-hosted-web-logic-server-c-soap-client

So my main target now is add the http header in .NET 4.0? and finally find the solution here
http://stackoverflow.com/questions/11509053/adding-http-headers-to-a-service-reference-service-method

Combining these two link, the solution would be
1. create the two class HttpHeaderMessageInspector and HttpHeadersEndpointBehavior from the second link
2. use the following code on your soap client


        Dim code() As Byte = System.Text.Encoding.ASCII.GetBytes(String.Format("{0}:{1}", userName, password))
        Dim b64str As String = Convert.ToBase64String(code)
        Dim header As New Dictionary(Of String, String)
        header.Add("Authorization", "Basic " & b64str)
        soapClient.Endpoint.Behaviors.Add(New HttpHeadersEndpointBehavior(header))


and then when call, it will do the authentication successfully without error






Wednesday, June 5, 2013

.Net PrintDocument.Print throw the handle is invalid

I have faced this issue when I have .Net command line program which call from a window service in order to print a document to the printer. The program can be run successfully when I call it from the commend line but it will throw this error when it is triggered from a window service.

Finally I find out that when I set the target CPU to "Any CPU", it runs successfully. Originally is set to "x86" and my OS is x64

It has wasted me half day to find out and sounds to me strange that the "x86" target CPU should be more generic for compatibility, but it will have error in such case. may be the caller window service is x64 and so the command line program is required to align with it.



Monday, May 6, 2013

ASP.NET AJAX Extension XML web services not work in IE10

This problem occurs when you are
  1. Using ASP.NET AJAX Extension to call web services (no matter 1.1 or the one in .net 3.0)
  2. Your web services return an XML node and the response format of script method set to XML instead of JSON
  3. Using IE10 as the browser
Then you will find that, the callback of the web service just give you a null result and nothing more.

After searching the google and find that there are little information regarding the problem, and the only hints I find is that the IE10 change to use the document as the default response type instead of an XML document. After debug into the ScriptResource.axd and find that inside the function get_xml of XMLHttpExecutor, there is a line a.setProperty that throw an Exception and this cause the result to be null.

The object is a document object while it expect that it is an xml object, and it seems match with the finding in google. The solution to that is to change the responseType of the XMLHttpRequest to "msxml-document" but as the XMLHttpRequest actually is generated in the ScriptResource.axd automatically, so we need to do something to override it.

So the final solution is to override the executeRequest function after the page load as follow

Sys.Net.XMLHttpExecutor.prototype.executeRequest = function () {
this._webRequest = this.get_webRequest();
var c = this._webRequest.get_body(), a = this._webRequest.get_headers();
this._xmlHttpRequest = new XMLHttpRequest;
this._xmlHttpRequest.onreadystatechange = this._onReadyStateChange;
var e = this._webRequest.get_httpVerb();
this._xmlHttpRequest.open(e, this._webRequest.getResolvedUrl(), true);
if (a)
  for (var b in a) {
    var f = a[b];
    if (typeof f !== "function")
      this._xmlHttpRequest.setRequestHeader(b, f)
  }
  if (e.toLowerCase() === "post") {
    if (a === null || !a["Content-Type"])
      this._xmlHttpRequest.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
    if (!c)
      c = ""
  }
// only add this line
  try { this._xmlHttpRequest.responseType = "msxml-document"; } catch (err) { }
  var d = this._webRequest.get_timeout();
  if (d > 0)
    this._timer = window.setTimeout(Function.createDelegate(this, this._onTimeout), d);
  this._xmlHttpRequest.send(c);
  this._started = true
}

The whole function are copied from the auto generated script, and only added one line to change the responseType of the XMLHttpRequest.

However, according to the Microsoft, it seems to be a temporary solution and finally need to migrate to use other method.....anyway hope this can help someone who did not find out a solution for that problem.

Monday, March 25, 2013

Ext JS 4.2 with .Net Web Service for CRUD grid

Here a step by step guide to teach how to use the Ext JS 4.2 with the .Net web service as backend for a CRUD grid, and of course with a complete example.

1. Let starts by create an empty web application. New Project > ASP.NET empty web application


2. Copy necessary files from the Ext JS package and you should have your project like this. I have keep the original path for those files so you should find those from the Ext JS package.


3. Next create a html page and drag all necessary path to the page as below.

<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title></title>
        <link href="examples/shared/example.css" rel="stylesheet" type="text/css" />
        <link href="resources/css/ext-all-neptune-rtl-debug.css" rel="stylesheet" type="text/css" />
        <link href="resources/ext-theme-neptune/ext-theme-neptune-all-rtl-debug.css" rel="stylesheet" type="text/css" />
        <script src="ext-all-debug.js" type="text/javascript"></script>
        <script src="examples/shared/examples.js" type="text/javascript"></script>
        <script src="examples/restful/restful.js" type="text/javascript"></script>
    </head>
    <body></body>
</html>
4. Up to now all client stuff is complete except a little modification on the javascript, which will leave on the last step. Next we go back to the server side and add our web service. Right click on the web project and add an AJAX-enabled WCF service and name it PersonService.


5. Next let define the Person Object such that it match with the model in the sample javascript. For demo purpose, I just put it inside the PersonService class.
        // the person model align with the restful sample
        [DataContractAttribute]
        public class Person
        {
            [DataMemberAttribute]
            public int id { get; set; }
            [DataMemberAttribute]
            public string email { get; set; }
            [DataMemberAttribute]
            public string first { get; set; }
            [DataMemberAttribute]
            public string last { get; set; }
            public Person(int id, string email, string first, string last)
            {
                this.id = id;
                this.email = email;
                this.first = first;
                this.last = last;
            }
        }

6. I want the grid support remote sorting, so I need one more class for the sorting parameter and will be used later also. The class as follow:
        public class sortPara
        {
            public string property;
            public string direction;
        }

7. Again for demo purpose, I want to show some data and use a static variable to store the list, so i create the following stuff again in the PersonService class.
        static List<Person> _pList = null;
        static int _id = 0;
        // let init and get some data to show
        private static List<Person> GetList()
        {
            if (_pList == null)
            {
                _pList = new List<Person>();
                _pList.Add(new Person(1, "fred@flintstone.com", "Fred", "Flinstone"));
                _pList.Add(new Person(2, "wilma@flintstone.com", "Wilma", "Flinstone"));
                _pList.Add(new Person(3, "pebbles@flintstone.com", "Pebbles", "Flinstone"));
                _pList.Add(new Person(4, "barney@rubble.com", "barney", "rubble"));
                _pList.Add(new Person(5, "betty@rubble.com", "betty", "rubble"));
                _pList.Add(new Person(6, "bambam@rubble.com", "bambam", "rubble"));
                _id = 7;
            }
            return _pList;
        }

8. Finally we create the four services for handling the CRUD request from Ext Grid. Please note that the read request require a Get request while other is Post request. The read request has 3 input parameter, the start, limit and the sort, which i did not handle the start and limit here. It would be easy to do so when your data come from a database.

        [OperationContract]
        [WebGet(RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
        public List<Person> GetPersonList(int start, int limit, sortPara[] sort)
        {
            List<Person> pList = GetList();
            // handle sorting
            foreach (sortPara sp in sort)
            {
                if (sp.property == "id" && sp.direction == "ASC")
                {
                    pList = pList.OrderBy(o => o.id).ToList();
                }
                else if (sp.property == "id" && sp.direction == "DESC")
                {
                    pList = pList.OrderByDescending(o => o.id).ToList();
                }
                else if (sp.property == "email" && sp.direction == "ASC")
                {
                    pList = pList.OrderBy(o => o.email).ToList();
                }
                else if (sp.property == "email" && sp.direction == "DESC")
                {
                    pList = pList.OrderByDescending(o => o.email).ToList();
                }
                else if (sp.property == "first" && sp.direction == "ASC")
                {
                    pList = pList.OrderBy(o => o.first).ToList();
                }
                else if (sp.property == "first" && sp.direction == "DESC")
                {
                    pList = pList.OrderByDescending(o => o.first).ToList();
                }
                else if (sp.property == "last" && sp.direction == "ASC")
                {
                    pList = pList.OrderBy(o => o.last).ToList();
                }
                else if (sp.property == "last" && sp.direction == "DESC")
                {
                    pList = pList.OrderByDescending(o => o.last).ToList();
                }
            }
            return pList;
        }
        [OperationContract]
        [WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
        public Person CreatePerson(string email, string first, string last)
        {
            // create the object and add to list
            Person p = new Person(_id, email, first, last);
            _id += 1;
            GetList().Add(p);
            return p;
        }
        [OperationContract]
        [WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
        public Person UpdatePerson(int id, string email, string first, string last)
        {
            // look for the object by id and update it
            List<Person> obList = GetList();
            foreach (Person p in obList)
            {
                if (p.id == id)
                {
                    p.email = email;
                    p.first = first;
                    p.last = last;
                    return p;
                }
            }
            return null;
        }
        [OperationContract]
        [WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
        public Person DeletePerson(int id)
        {
            // delete the object from list
            List<Person> obList = GetList();
            foreach (Person p in obList)
            {
                if (p.id == id)
                {
                    obList.Remove(p);
                    return p;
                }
            }
            return null;
        }

9. The last step is to modify the restful.js such that it call my web service instead of the original REST one. look for the definition of proxy and change it to following

         proxy: {
            type: 'ajax',
            // Call web service method using GET syntax
            api: {
                read: 'PersonService.svc/GetPersonList',
                create: 'PersonService.svc/CreatePerson',
                update: 'PersonService.svc/UpdatePerson',
                destroy: 'PersonService.svc/DeletePerson'
            },
            reader: {
                type: 'json',
                root: 'd'
            }
        },

10. Also we want to support remote sorting so i add the following to the store object also
        remoteSort: true,
        sorters: [{
            property: 'id',
            direction: 'ASC'
        }],

11. finally after build, go to the sample.htm and you should get a nice grid





password : nothing



Monday, January 21, 2013

Javascript to validate HKID number

When i looking for script to validate HKID, I find that most of the available script did not cater for two character prefix case and thus is not really valid to use. Therefore I have write my own which also allow to handle the bracket for the check digit.


function IsHKID(str) {
    var strValidChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"

    // basic check length
    if (str.length < 8)
        return false;
 
    // handling bracket
    if (str.charAt(str.length-3) == '(' && str.charAt(str.length-1) == ')')
        str = str.substring(0, str.length - 3) + str.charAt(str.length -2);

    // convert to upper case
    str = str.toUpperCase();

    // regular expression to check pattern and split
    var hkidPat = /^([A-Z]{1,2})([0-9]{6})([A0-9])$/;
    var matchArray = str.match(hkidPat);

    // not match, return false
    if (matchArray == null)
        return false;

    // the character part, numeric part and check digit part
    var charPart = matchArray[1];
    var numPart = matchArray[2];
    var checkDigit = matchArray[3];

    // calculate the checksum for character part
    var checkSum = 0;
    if (charPart.length == 2) {
        checkSum += 9 * (10 + strValidChars.indexOf(charPart.charAt(0)));
        checkSum += 8 * (10 + strValidChars.indexOf(charPart.charAt(1)));
    } else {
        checkSum += 9 * 36;
        checkSum += 8 * (10 + strValidChars.indexOf(charPart));
    }

    // calculate the checksum for numeric part
    for (var i = 0, j = 7; i < numPart.length; i++, j--)
        checkSum += j * numPart.charAt(i);

    // verify the check digit
    var remaining = checkSum % 11;
    var verify = remaining == 0 ? 0 : 11 - remaining;

    return verify == checkDigit || (verify == 10 && checkDigit == 'A');
}