Search This Blog

Tuesday, June 28, 2011

Make NHibernate work with SQL server 2008 express and c# express 2008

This article shows how to using NHibernate with SQL server 2008 express and c# 2008 express edition. I will make a simple calculation service in WCF, save and retrieve the calculation history in MS SQL database using NHibernate. At last, I will make a winform client to call the service.

1.    MS SQL server 2008 express need to be installed.
2.    Download and install SQL server management studio express at
http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=7593
Remember to install 3 prerequisites - .Net framework 3.5 SP1, Windows Installer 4.5, Windows PowerShell 1.0 before installing SQL server management studio express. Links to these programs can be found on SQL server management studio express download page.
3.    Before we go more detail into implementation of the WCF services, we need to create database and setup proper user privileges in MS SQL server.
4.    start sql server configuration manager and make sure SQL server(SQL Express) is running

Start sql server management studio and login with default windows authentication
Create a new database ‘calculationservice’
Now I created a new user ‘calculationuser’ under Security->Logins folder, and check SQL Server authentication box, set password and select default database to calculationservice.
 
Check ‘db_owner’ and ‘public’ checkboxes.
Make sure connection to database is granted and login is enabled.
So next time I log in Sql server management studio, I can use sql authentication and the user name, password just defined.

5.    Now database configuration is ready, let’s start to make some code. I created a solution ‘CalculationService’ in Visual studio c# 2008 express.
6.    I then created a project ‘CalculationServiceHost’ which as the name indicates is a service host project, it also contains the integration code and configuration to MS SQL Database using NHibernate.
7.    I defined 2 service contracts ICalculate and IHistory,

      [ServiceContract(Namespace = "http://Xish.Project.CalcultionService")]
    public interface ICalculate
    {
        [OperationContract]
        double operate(double o1, double o2, string op);
    }
    [ServiceContract(Namespace = "http://Xish.Project.CalcultionService")]
    public interface IHistory
    {
        [OperationContract]
        List<OperationUnit> getCalculationHistory();
    }
8.    Download NHibernate from http://nhforge.org
Import following dll into project
LinFu.DynamicProxy.dll, NHibernate.ByteCode.LinFu.dll, NHibernate.Mapping.Attributes.dll, NHibernate.dll

9.    Then I created a hibernate schema xml file which defines the data mapping structure of the calculation unit.


<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
    namespace="CalculationService.Host" assembly="ServiceHost">

  <class name="OperationUnit" table="OperationUnit">
    <id name="ID" column="Id">
      <generator class="increment"/>
    </id>
    <property name="OPERAND1" column="Operand1"/>
    <property name="OPERAND2" column="Operand2"/>
    <property name="OPERATOR" column="Operator"/>
    <property name="RESULT" column="Result"/>
  </class>

</hibernate-mapping>

10.    Following code shows how to use NHibernate to save a calculation unit record,
 
ISession session = NHibernateHelper.GetCurrentSession();

            ITransaction tx = session.BeginTransaction();

            session.Save(opunit);
            tx.Commit();

            NHibernateHelper.CloseSession();

11.    Following code shows how to use NHibernate to retrieve calculation history,
ISession session = NHibernateHelper.GetCurrentSession();

            ITransaction tx = session.BeginTransaction();

            IQuery query = session.CreateQuery("from OperationUnit where Id>0");
            List<OperationUnit> templist = query.List<OperationUnit>() as List<OperationUnit>;
            tx.Commit();

            NHibernateHelper.CloseSession();

 12.    Next step is to add NHibernate configurations in app.config file. If it is the first time you run the application, uncomment hbm2dll.auto property. Once NHibernate transaction is called, it will automatically generate new tables in the database based on definitions found in hhibernate schema files. Next time, you may want to comment it out if you don’t want to override existing tables.
 
    <configSections>
    <section
        name="log4net"
        type="log4net.Config.Log4NetConfigurationSectionHandler,log4net"
               />
    <section name="hibernate-configuration"
         type="NHibernate.Cfg.ConfigurationSectionHandler, NHibernate" />
  </configSections>

  <!-- Add this element -->
  <hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
    <session-factory>
      <property name="dialect">NHibernate.Dialect.MsSql2008Dialect</property>
      <property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
      <property name="connection.connection_string">Server=localhost\SQLEXPRESS;initial catalog=calculationservice;User Id=calculationuser;Password=calculationpassword;Integrated Security=True;MultipleActiveResultSets=True</property>
      <property name="proxyfactory.factory_class">NHibernate.ByteCode.LinFu.ProxyFactoryFactory, NHibernate.ByteCode.LinFu</property>
      <!--property name="hbm2ddl.auto">create</property-->
      <mapping assembly="ServiceHost" />
    </session-factory>
  </hibernate-configuration>

13. Follwing code create a service host and make it running and waiting for service request.

Uri baseAddress = new Uri("http://localhost:8000/XishService");

            // Step 2 of the hosting procedure: Create ServiceHost
            ServiceHost selfHost = new ServiceHost(typeof(CalculationService), baseAddress);

            try
            {


                // Step 3 of the hosting procedure: Add service endpoints.
                selfHost.AddServiceEndpoint(
                    typeof(ICalculate),
                    new WSHttpBinding(),
                    "Calculation");

                selfHost.AddServiceEndpoint(
                    typeof(IHistory),
                    new WSHttpBinding(),
                    "History");


                // Step 4 of the hosting procedure: Enable metadata exchange.
                ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
                smb.HttpGetEnabled = true;
                selfHost.Description.Behaviors.Add(smb);

                // Step 5 of the hosting procedure: Start (and then stop) the service.
                selfHost.Open();
                Console.WriteLine("The service is ready.");
                Console.WriteLine("Press <ENTER> to terminate service.");
                Console.WriteLine();
                Console.ReadLine();

                // Close the ServiceHostBase to shutdown the service.
                selfHost.Close();
            }
            catch (CommunicationException ce)
            {
                Console.WriteLine("An exception occurred: {0}", ce.Message);
                selfHost.Abort();
            }


14.    We are done with the host part, now I am going to create a winform client ‘CalculationServiceClient’ which should consume the services.
15.    I need to create a proxy class from the webservices. To do so, I run following command in visual studio 2008 command prompt.
  svcutil http://localhost:8000/XishService /language:C# /out:Proxy.cs /noConfig
It will generate a proxy class with which I can call the calculation services in the client.
16.    Add service endpoints in app.config
 
<configuration>
    <system.serviceModel>
        <client>
            <endpoint address="http://localhost:8000/XishService/Calculation"
                binding="wsHttpBinding"
                contract="ICalculate" name="WSHttpBinding_ICalculate">
            </endpoint>
            <endpoint address="http://localhost:8000/XishService/History"
                binding="wsHttpBinding"
                contract="IHistory" name="WSHttpBinding_IHistory">
            </endpoint>
        </client>
    </system.serviceModel>
</configuration>

 17.    Using the webservice client classes defined in proxy class to call services  as shown below.
 
CalculateClient proxy = new CalculateClient("WSHttpBinding_ICalculate");
            double result = proxy.operate(Convert.ToDouble(operand1Tbx.Text), Convert.ToDouble(operand2Tbx.Text), operatorTbx.Text);

HistoryClient proxy = new HistoryClient("WSHttpBinding_IHistory");
            CalculationService.Host.OperationUnit[] operationunits = proxy.getCalculationHistory();
            historyTbx.Clear();
18.    We are done. When I press calculate button, the client will call the calculation service to return a result and save the operation in database. When I press history button, the client will call the getHistory service to return calculation history and display in the text box in client.






4

What is an ESB - Enterprise Service Bus

An Enterprise Service Bus perform following between requestor and service,
·         Routing messages between services.
·         Converting transport protocols between requestor and service.
·         Transforming message formats between requestor and service.
·         Handling business events from disparate sources.

Monday, June 27, 2011

Days of difference Calculation

How to calculate the total days between 2 dates without using programming language specific features? At the moment I was given the question, I have no idea, because I don’t know how to get a precise day number for each year. After like 20 minutes (I react slowly sometimes), I realized that there is a solution.
I recalled in Chinese calendar there is a leap year for around every 4 years. The exact rule for leap year is a bit complex, I checked google and found some adequate to use answers. Suppose we already have a function leapyear(y) which returns 1 to indicate a year is leap year or 0 for not a leap year, we then have a solution. I put the pseudo code below,
Int function getDaysOfYear(var year)
{
Case(leapyear(year)){
Case 0: daysOfYear = 365; break;
Case 1: daysOfYear = 366; break; // leap year has 366 days
}
Return daysOfYear;
}

int function getDaysOfMonth(var month, var year)
{
If (leapyear(year) and month==2)
{
month = 0;
}
case(month) {
1, 3, 5, 7, 8, 10, 12: daysOfMonth = 31; break;
0: daysOfMonth = 29; break; // leap year’s February month only have 29 days
2: daysOfMonth = 28; break; // normal year’s February month only have 28 days
 4, 6, 9, 11: daysOfMonth = 30; break;
Other: break;
}
Return daysOfMonth;
}

Int daysOfDifference(var d1, var d2)
{
If (d1 > d2) swap(d1, d2);
// get days of all the years in between
For (int i=d1.y; i<d2.y; i++)
{
Days  += getDaysOfYear(i);
}
If (d1.m <= d2.m)
{
For (int j=d1.m; j<d2.m; j++)
{
Days += getDaysOfMonth(j);
}
} else
{
For (int j=d2.m; j<d1.m; j++)
{
Days -= getDaysOfMonth(j);
}
}
Days += d2.d – d1.d;
Return days;
}
Now we will handle the function leapyear(var year)
I’m giving a Gregorian calendar leapyear calculation method below, It is still not 100% accurate for very big years (much larger than 172800).

There are 3 rules for judging a leap year,
1.       Year can be devided by 4, but not by 100
2.       Year can be devided by 400, but not by 3200
3.       Year can be devided by both 3200 and 172800
int leapyear(int year)
{
if (((year%3200)&&(year% 172800))||((year%400==0)&&(year%3200!=0)) || (year%100!=0) && (year%4==0))
 return 1;
else
return 0;
}
Any genius answers to the days of difference question is more than welcome to add.

Wednesday, June 8, 2011

Game Bot for javascript powered webgame

I made a few game bots for a web game powered by javascript. First ting to clarify is that I made it in my free time and played it in my free time.:) I started with a VB.Net version and later on changed to C#.
So basically, I want to show you how to make such a gamebot in this post.
First drag a System.Windows.Forms.WebBrowser control to your form, let’s say the control variable is webBrowser1. To call a javascript function, use code similar to following sample,

Me.WebBrowser1.Document.Window.Frames(0).Document.Window.Frames(0).Document.InvokeScript("cmd", _
                                         New Object() {fightcmd})

This line of code first gets to the frame where javascript function is defined, then call the function ’cmd’ with one parameter ’fightcmd’.
That’s simple isn’t it? We are half way there, there is a thread problem we need to handle.
Aside from the main thread – a form containing the webBrowser control, we need to define a background thread calling all the movements, fighting, talking functions. If we use the code above directly inside the background thread, there will be a cross thread violation (cross thread violation, control was accessed from one thread other that it was created). To solve the problem, we need to define delegate functions.

Private Function GetHP() As Integer
        Dim hp As Integer = 0
        Dim HpSpan As HtmlElement = Me.WebBrowser1.Document.Window.Frames(0).Document.Window.Frames(0).Document.GetElementById("hpLine_left_no")
        hp = Val(HpSpan.InnerText)
        Return hp
    End Function
                                     Above code is defined in main thread

Public Delegate Function GetHPDelegate() As Integer
Public Class Controller
Private m_gethp As GetHPDelegate
Public Sub New(ByRef caller As Form1, _
               ByRef gethp As GetHPDelegate, _
               …)
Private Sub Fight()
hp = m_BaseControl.Invoke(m_gethp)
End Sub
End Class
                                               Above code is defined in background thread

So problem 80% solved.
Next issue is a bit tricky, what if the javascript function is called only by object. I didn’t find a direct way to call such a function. However, gamebot usually only simulates human actions. And human actions in a webgame is clicking links. So if we can find a way to call those link clicking actions, we find a way to call those hidden javascript functions indirectly. Let’s see an example below,
Let’s say on the webpage, there is a tag element img by clicking which will trigger a javascrpt function p.closeTask().
<div id=”renPicX”><img onclick=”p.closeTask()”/></div>
public void closeTakeTaskWin()
        {
            HtmlElement renPicX = getHtmlElementById("renPicX");
            HtmlElement imgEl = renPicX.GetElementsByTagName("img")[0];
            object obj = imgEl.DomElement;
            System.Reflection.MethodInfo mi = obj.GetType().GetMethod("click");
            mi.Invoke(obj, new object[0]);
        }
By using above code we can call the onclick method in img element and trigger the p.closeTask() javascript function.
With above 3 basic techniques, webbot’s functionalities should suffice.
Since it is a chinese webgame called (猫游记), I don’t think too many of you will have interest in source code. However if you happen to play the game and have interest in some code, leave your email address in the comment and I will send to you.