Saturday, March 3, 2012

Microsoft Dynamics CRM 2011 for Developers

Accessing Microsoft Dynamics CRM 2011 using WCF

Contents
  1. Introduction
  2. Creating a client application
  3. Using the Discovery Service
  4. Using the Organization Service
  5. Working with CRM Data
    1. Late Binding Approach
      1. Using RetrieveMultiple method
      2. Using Retrieve method
      3. Using Update method
      4. Using Delete method
      5. Using Create method
    2. Early binding Approach
      1. generating Client Types
      2. Enable ProxyTypeBehavior
      3. Using RetrieveMultiple method
      4. Using Retrieve method
      5. Using Create method

Introduction

Microsoft Dynamics CRM is a Customer Relationship Management software package developed to focus mainly on Sales, Marketing, and Service (help desk) sectors. The Microsoft Dynamics family of business applications includes other related products such as Microsoft Dynamics AX, Microsoft Dynamics GP, Microsoft Dynamics NAV, and Microsoft Dynamics SL.

Basically, Dynamics CRM is a client-server web application that supports extensive web services interfaces. Dynamics CRM 2011 introduces a new WCF interface for working with data, services and metadata.

Microsoft Dynamics CRM supports two kinds of deployments: Online, on-premises. You can signup for 30 days free trial at http://crm.dynamics.com/en-us/trial-overview. This will provide you with 30 days full functioning online version of Dynamics CRM. We will you this version in this post and the upcoming posts.

There is a lot of situations where organizations want to gain more benefit of its Dynamics CRM deployment than what Dynamics CRM can offer through its built-in customization tools. Based on the situation, you as a developer may be required to develop applications that interact with Dynamics CRM through its web services interfaces or develop applications that run within Dynamics CRM itself.

In this post we will explore one of the techniques of interacting with Dynamics CRM through its web services interfaces. We will build a windows forms application that connects to the online version of Dynamics CRM 2011, retrieve data from it, and manipulate its data. To continue with this post you need to signup for an online trial version and to install Microsoft Dynamics CRM 2011 Software Development Kit (SDK) ( download from http://www.microsoft.com/download/en/details.aspx?id=24004 )

Step 1: Create a client application

Simply create a new windows forms application. Right click your project in the solution explorer and select properties, locate the Target Framework drop down and change it from .Net Framework 4 Client Profile to .Net Framework 4. Add references to System.Runtime.Serialization.dll and System.ServiceModel.dll and System.Security. Add references to Microsoft.Xrm.Sdk.dll and Microsoft.Crm.Sdk.Proxy.dll (both files located in the Bin folder in your CRM SDK installation directory). Right click on the project in the solution explorer and click Add existing, browse to %CRMSDK%\samplecode\cs\helpercode\deviceidmanager.cs

The DeviceIdManager class is included in the Dynamics CRM SDK to register a computing device with Windows Live ID through the generation of a Device ID and password. Then it optionally stores that information in an encrypted format on the local disk for later use. This functionality is required when authenticating with Microsoft Dynamics CRM online. The device registration is stored in %USERPROFILE%\LiveDeviceID\LiveDevice.xml. It looks like:

<?xml version="1.0"?>


AQAAANCMnd8BFdERjHoAwE/Cl+sBAAAAooZFtct7dEyyPUNu1eZujgAAAAACAAAAAAADZgAAqAAAABAAAAD0860vIxbs57z9CgRRPAtTAAAAAASAAACgAAAAEAAAAFL9eqV3G5WLFhHYAkX1/z8gAAAAZjBYCltk8cNwuydeQK70t9/txdmoJhIGeN2StJbyx9EUAAAAY10YU7QprX0EO5Fq43A/S2Wer2I=



The CRM SDK team is separating the more CRM specific types from the xRM Application Framework related types.  The Microsoft.Xrm.Sdk assembly will provide all the low-level types necessary for basic operation against the xRM Application Framework. The Microsoft.Crm.Sdk.Proxy.dll  assembly will abstract away much of the complexity of dealing with the WCF services directly.



Now, try to make your application interface like the one in the image below.



app



Now we created the application interface, added the required references, and ready for the real thing :)



Step 2: Using the Discovery Service



The discovery service allows you to explore and enumerate the organizations on a certain CRM server and the web services endpoint URL needed to access the Organization Services web service for each of these organizations (The CRM server can contain multiple organizations). We will use this information later to configure the organization web service proxy and call web service methods to access the organization’s data and metadata. The service respects security such that it will only return those organizations to which a user has access. The discovery service is accessed using methods on the IDiscoveryService interface. The DiscoveryServiceProxy class is a helper class to make it easier to get instances of IDiscoveryService without having to deal with all the WCF low-level details.



Now on the forms designer surface double click on the Discover button to add event handler and open the MainWindow.xaml.cs code behind file. In the code behind, add the following using statements:



using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Client;
using Microsoft.Xrm.Sdk.Discovery;
using System.ServiceModel.Description;
using Microsoft.Crm.Services.Utility;
using Microsoft.Xrm.Sdk.Query;
using Microsoft.Xrm.Sdk.Messages;


Inside the frmMain class, add the following private properties to hold references to the organization details (the Discovery service and the Organization service).



private OrganizationDetail CurrentOrganizationDetail { get; set; }
private IDiscoveryService DiscoveryService { get; set; }
private OrganizationServiceProxy OrgService { get; set; }
private ClientCredentials _ClientCreds { get; set; }
private ClientCredentials _DeviceCreds { get; set; }
private bool IsLiveID { get; set; }


Now, let's add to frmMain class a helper method to builds the full Uri of the discovery service.



        public Uri GetDiscoveryServiceUri(string serverName)
{
string discoSuffix = @"/XRMServices/2011/Discovery.svc";

return new Uri(string.Format("{0}{1}", serverName, discoSuffix));
}


Next, In the event handler for the Discover button, add the following code to use the ServiceConfigurationFactory helper class to get an instance of the Discovery service configuration. This returned as an IServiceConfiguration<IDiscoveryService> type that hides and simplifies some of the lower level WCF configuration.



var discoUri = GetDiscoveryServiceUri(ServerURL.Text);
IServiceConfiguration dinfo = ServiceConfigurationFactory.CreateConfiguration(discoUri);


Different credentials are needed for CRM online vs. on premises. To differentiate between them we will add the following GetServerType helper method.



public AuthenticationProviderType GetServerType(Uri uri)
{
return ServiceConfigurationFactory.CreateConfiguration(uri).AuthenticationType;
}


Now, we will return to the Discover button handler. The follwoing code will create a DiscoveryServiceProxy instance based on the server type we connecting to (on-line or on-premises). Note that DeviceIdManager class have been used only in the on-line scenario. Then we use this instance (DiscoveryServiceProxy) to connect to the server, authenticate, and execute our RetrieveOrganizationsRequest to get RetrieveOrganizationResponse. This response has a property OrganizationDetails that is an array of OrganizationDetail objects which we will use to fill the oragnizations combo box. Add the following code to the couple of lines that you are added to btnDiscover_click handler.



_ClientCreds = new ClientCredentials();
DiscoveryServiceProxy dsp;

if (GetServerType(discoUri) == AuthenticationProviderType.LiveId)
{
_ClientCreds.UserName.UserName = username.Text;
_ClientCreds.UserName.Password = password.Text;

_DeviceCreds = DeviceIdManager.LoadOrRegisterDevice();

dsp = new DiscoveryServiceProxy(discoUri, null, _ClientCreds, _DeviceCreds);
IsLiveID = true;
}
else
{
_ClientCreds.Windows.ClientCredential.UserName = username.Text;
_ClientCreds.Windows.ClientCredential.Password = password.Text;
_ClientCreds.Windows.ClientCredential.Domain = domain.Text;

dsp = new DiscoveryServiceProxy(dinfo, _ClientCreds);
IsLiveID = false;
}

dsp.Authenticate();
var orgRequest = new RetrieveOrganizationsRequest();
var orgResponse = dsp.Execute(orgRequest) as RetrieveOrganizationsResponse;
comboOrgs.ItemsSource = orgResponse.Details;


You can now check your frmMain.cs aginst the below code. If everything is Ok, hit F5, enter the user name/password you used in your 30-days free trial signup (or your active directory credentials, if you test against your on-premises deployment), click Discover button. You will see the organizations combo box filled with the available organizations on this server that you have access to.



using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Collections;

using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Client;
using Microsoft.Xrm.Sdk.Discovery;
using System.ServiceModel.Description;
using Microsoft.Crm.Services.Utility;

using Microsoft.Xrm.Sdk.Query;
using Microsoft.Xrm.Sdk.Messages;

namespace xRM_Demo01
{
public partial class frmMain : Form
{
private OrganizationDetail CurrentOrganizationDetail { get; set; }
private IDiscoveryService DiscoveryService { get; set; }
private IOrganizationService OrgService { get; set; }
private ClientCredentials _ClientCreds { get; set; }
private ClientCredentials _DeviceCreds { get; set; }
private bool IsLiveID { get; set; }
public frmMain()
{
InitializeComponent();
}

private void btnDiscover_Click(object sender, EventArgs e)
{
var discoUri = GetDiscoveryServiceUri(txtServer.Text);

IServiceConfiguration dinfo =
ServiceConfigurationFactory.CreateConfiguration(discoUri);
_ClientCreds = new ClientCredentials();
DiscoveryServiceProxy dsp;

if (GetServerType(discoUri) == AuthenticationProviderType.LiveId)
{
_ClientCreds.UserName.UserName = txtUserName.Text;
_ClientCreds.UserName.Password = txtPassword.Text;

_DeviceCreds = DeviceIdManager.LoadOrRegisterDevice();

dsp = new DiscoveryServiceProxy(discoUri, null, _ClientCreds, _DeviceCreds);
IsLiveID = true;
}
else
{
MessageBox.Show("This is not a valid Microsoft Dynamics CRM online URL");
return;
}

dsp.Authenticate();
var orgRequest = new RetrieveOrganizationsRequest();
var orgResponse = dsp.Execute(orgRequest) as RetrieveOrganizationsResponse;
comboOrgs.DataSource = orgResponse.Details;
comboOrgs.DisplayMember = "FriendlyName";
comboOrgs.ValueMember = "UrlName";
}
public Uri GetDiscoveryServiceUri(string serverName)
{
string discoSuffix = @"/XRMServices/2011/Discovery.svc";

return new Uri(string.Format("{0}{1}", serverName, discoSuffix));
}
public AuthenticationProviderType GetServerType(Uri uri)
{
return ServiceConfigurationFactory.CreateConfiguration(uri).AuthenticationType;
}


Step 3: Using the Organization Service



The organization service is the endpoint that you will use to interact with an individual organization's data and metadata services. It accessed using the methods on the IOrganizationService interface. The OrganizationServiceProxy helper class is used to make it easier to get instance of IOrganizationService without dealing with the WCF low-level details. Double click on the Connect button to add an event handler for it and add the following code.



            if (comboOrgs.SelectedItem == null)
{
MessageBox.Show("You must select an organization before connecting");
return;
}
this.CurrentOrganizationDetail = comboOrgs.SelectedItem as OrganizationDetail;
Uri orgServiceUri = new Uri(CurrentOrganizationDetail.Endpoints[EndpointType.OrganizationService]);
if (IsLiveID)
{
OrgService = new OrganizationServiceProxy(orgServiceUri, null, _ClientCreds, _DeviceCreds);
}
else
{
IServiceConfiguration orgConfigInfo =
ServiceConfigurationFactory.CreateConfiguration(orgServiceUri);
OrgService = new OrganizationServiceProxy(orgConfigInfo, _ClientCreds);
}


The added code checks that you selected an organization, get the select organization as an OrganizationDetail object, use the EndPoints of this object to get the Uri of the Organization Service. Then use this information and the client credentials and the device credentials to create an object of OrganizationServiceProxy.



Now we are ready to start interacting with the organization service through this proxy (which will be the next step). If you want to ensure that you did everything right, you can try send a simple request to the organization service and see the result. To do so, we can send the WhoAmI message to the service and receive the response (the ID of the logged in used). Add a using statement for Microsoft.Crm.Sdk.Messages. Add the following code to the end of btnConnect_click to test your connectivity.



WhoAmIRequest req = new WhoAmIRequest();
var response = OrgService.Execute(req) as WhoAmIResponse;
MessageBox.Show("You are connected as userid " + response.UserId.ToString());


Run, put your credentials an server, click Discover, choose your organization from the combo box and click connect. You will get something like the below image.



msg



Step 4: Working with the CRM data



Early versus Late-Bounding In Microsoft Dynamics CRM 2011, you can choose from several programming styles to find the model that best fits your situation.




In Early-Bound style, you create a class for each business entity in your CRM deployment. You will use these classes to access business data in your CRM deployment. There is a code generation tool included in the %CRMSDK%\bin called crmsvcutil.exe that will generate early-bound entity classes for you. It works with on-premises and online deployments. Every time you make customizations to your entities, you have to run this tool to regenerate these classes again. The advantages of using early-bound entity classes is that all type references are checked at compile time. You will also enjoy the intellisense support.



In Late-Bound style, you can work with the data in CRM without having classes representing each data entity in the organization. Most Probably, you will use this style when working with entities (or customizations) that you can’t anticipate at the development time.




In this step we will work with the CRM data using late-bound style to retrieve all accounts data in our CRM, update it, save it, and add new records also.



Method : RetrieveMultiple



To retrieve multiple records from Dynamics CRM, we use the RetrieveMultiple of the organization service and pass a QueryExpression object to it. QueryExpression holds all the information required to get the desired data from Dynamics CRM. To construct the Query expression you need:




  • ColumnSet object to specify the columns we need to retrieve.


  • ConditionExpression object to hold any conditions we will use to filter the returned rows.


  • FilterExpression object to hold all the ConditionExpression objects we use in our query. This enables us to make complex queries.


  • EntityName a string property used to specify the entity the query runs against.


  • You can also order the returned data through method AddOrder(“columnName”, OrderType). OrderType is an enumeration have the values Ascending and Descending.



For Simplicity we will retrieve columns name and accountid of all account type records in CRM. Because we using late-bound style, we get the results into EntityCollection collection. We enumerate through the returned collection, and put the entities into a list of custom objects of type Item. Then we bind our accounts combobox to this list.



            ColumnSet cs = new ColumnSet();
cs.AddColumns("name", "accountid");

QueryExpression qe = new QueryExpression();
qe.ColumnSet = cs;
qe.EntityName = "account";

EntityCollection accountList = OrgService.RetrieveMultiple(qe);
List accounts = new List();
comboAccounts.ValueMember = "Value";
comboAccounts.DisplayMember = "Name";
for (int i = 0; i < accountList.Entities.Count; i++ )
{
accounts.Add(new Item(accountList[i].Attributes["name"].ToString(),
accountList[i].Attributes["accountid"].ToString()));
}
comboAccounts.DataSource = accounts;
}


Also add the following class into your solution namespace, which holds the acounts name and accountid to bind it to the combobox.



    class Item
{
private string _name;
private string _value;
public string Name
{
get { return _name; }
set { _name = value; }
}
public string Value
{
get { return _value; }
set { _value = value; }
}
public Item(string p_name, string p_value)
{
Name = p_name;
Value = p_value;
}
}


Now you can run the application, connect to your organization, and check that the combobox is filled of your accounts data.



Method : Retrieve



Now we will use the accountid of the selected account in the combobox to get the rest of the account data. In this case we will use the Retrieve method of the organization service. This method retrieves just one record of the type specified in the first argument, designated by the key passed in the second argument. Double click on the accounts combobox to add an event handler for the SelectedIndexChanged event. Add the following code to this event handler to fill the form with the account data.



            ColumnSet cs2 = new ColumnSet(new string[] {"address1_city","address1_line1","address1_stateorprovince",
"name","industrycode"});
try
{
var account = OrgService.Retrieve("account", new Guid(comboAccounts.SelectedValue.ToString()), cs2);
txtName.Text = account.Attributes["name"].ToString();
txtCity.Text = account.Attributes["address1_city"].ToString();
txtAddress.Text = account.Attributes["address1_line1"].ToString();
txtState.Text = account.Attributes["address1_stateorprovince"].ToString();
}
catch (Exception ex)
{
MessageBox.Show("An error happened: " + ex.Message);
}


Method : Update



Now we can go farther and modify the current displayed account data and try to save it. To save any entity data into CRM, create an Entity object and pass the entity type into the constructor (it will be "account" in our case). Then set the attribute values you want and pass the updated entity to the organization service Update method. Add the following code the save button click event handler to realize the update operation.



 
try
{
Entity account = new Entity("account");
account.Attributes["accountid"] = new Guid(comboAccounts.SelectedValue.ToString());
account.Attributes["name"] = txtName.Text;
account.Attributes["address1_line1"] = txtAddress.Text;
account.Attributes["address1_city"] = txtCity.Text;
account.Attributes["address1_stateorprovince"] = txtState.Text;
OrgService.Update(account);
MessageBox.Show("Account updated successfully");
// TODO: reload the accounts combobox.
}
catch (Exception ex)
{
MessageBox.Show("An error occurred : " + ex.Message);
}


Method : Delete



To delete a record you use the Delete method of the organization service, pass the entity type name and its key like the following.



try
{
OrgService.Delete("account", new Guid(comboAccounts.SelectedValue.ToString()));
MessageBox.Show("Account deleted successfully");
// TODO: reload the accounts combobox
}
catch (Exception ex)
{
MessageBox.Show("An error occurred : " + ex.Message);
}


Now let's add code to clear the form in the clear button click event handler.



            txtName.Text = "";
txtCity.Text = "";
txtAddress.Text = "";
txtState.Text = "";


Method : Create



To insert a new record to CRM, we create an Entity object passing the entity name to its constructor, set its attributes, and pass it to the organization service Create method. Add the following code to the save new button click event handler.



try
{
Entity account = new Entity("account");
account.Attributes["name"] = txtName.Text;
account.Attributes["address1_line1"] = txtAddress.Text;
account.Attributes["address1_city"] = txtCity.Text;
account.Attributes["address1_stateorprovince"] = txtState.Text;
OrgService.Create(account);
MessageBox.Show("Account created successfully");
}
catch (Exception ex)
{
MessageBox.Show("An error occurred : " + ex.Message);
}


No we have examined almost all basic data operations on the CRM data using late-bounding style: RetrieveMultiple, Retrieve, Update, Delete, and Create new record.



Generating Client Types for Early Binding



Now we will use a different style than the one we used above. We will use the SDK tool crmsvcutil.exe to generate the typed classes for our CRM entities bsed on the metadata service of our CRM organization. These generated typed classes will inherit from the Entity class we worked with earlier in this post. Now follow the following steps to generate your typed classes:




  1. Open the project included in the SDK at %SDK%\tools\deviceregistration folder and build it.


  2. Open the command prompt cmd.exe and change directories to %SDK%\tools\deviceregistration\bin\Debug and run the command DeviceRegistration.exe /operation:Register This will generate a Device ID and Device Password for you (similar to the ones created by deviceidmanager.cs class).


  3. Copy the Deviceid and Device Password to a notepad. (if you are not familiar with cmd, right click the inside the window and click highlight, then highlight the desired text, then right click the cmd window title bar and click Edit>> copy.)


  4. In the command window, change the directories to %SDK%\bin and create a command like the following:



crmsvcutil.exe /url:<CRM Online Organization service URL> /out:<Output file name> /servicecontextName:<Organization name> /username:<LiveID> /password:<LiveIDPassword>


/deviceid:<Deviceid> /devicepassword:<DevicePassword> /namespace:<Namespace>



<CRM Online Organization service URL> will be like https://xrmdemo5.api.crm.dynamics.com/XRMServices/2011/Organization.svc? . You can find your URL by going to Settings >> Customizations >> Developer Resources, your URL will be there.



<Output file name> is the file name of the generated code (like GeneratedEntities.cs)



<Organization name> is your organization name.



<LiveID>, <LiveIDPassword> are your live credentials used for this organization.



<Deviceid>, <DevicePassword> are provided from step 3.



<Namespace> is the name space of the generated classes (may be YourCompanyname.YourOrganizationName)



the complete command may look like



crmsvcutil.exe /url:https://xrmdemo5.api.crm.dynamics.com/XRMServices/2011/Organization.svc /out:GeneratedEntities.cs /servicecontextName:xrmdemo5 /username:ebeid_soliman@hotmail.com /password:mypassword

/deviceid:11denl276oo3fgxbakccnnq2x4 /devicepassword:bH.iaG?c3rRi-`L,nKC0S4^^ /namespace:xRMDemo.Entities



Now we created our early bound entity classes. Let’s modify our application to use the early-bound entity classes that we generated.



Step 1: Add the generated types to the project



Right click on the project in the solution explorer and click Add existing, browse to %CRMSDK%\bin and add your generated file (its GeneratedEntities.cs in my above command).



Step 2: Enable proxy types



In order to use the generated types when dealing with the organization service, you have to add the ProxyTypesBehavior to the endpoint Behaviors collection. This instructs the OrganizationServiceProxy to look in the assembly for classes with certain attributes to use. The generated classes are already attributed with these attributes. Simply, this makes all interactions with the organization service to be done using the generated typed classes for each entity instead of the generic Entity class we used earlier.



Open the frmMain.cs, locate btnConnect_Click event handler and add the following line of code after the last section line that creates the new instance of our OrganizationServiceProxy.



OrgService.ServiceConfiguration.CurrentServiceEndpoint.Behaviors.Add(new ProxyTypesBehavior());


Method : RetrieveMultiple



It’s the same before. Now, let's modify the accounts combobox filling section to use the generated Account class instead of the Item class (you can get ride of it) that we created earlier. Modify the last section in btnConnect_Click event handler to look like the following.



List accounts = new List();
comboAccounts.ValueMember = "accountid";
comboAccounts.DisplayMember = "name";
for (int i = 0; i < accountList.Entities.Count; i++)
{
accounts.Add((Account)accountList[i]);
}
comboAccounts.DataSource = accounts;


Method : Retrieve



It almost the same, except we will use Account class and its properties instead of the Entity class and its attributes. Modify the comboAccounts_SelectedIndexChanged event handler to look like:



ColumnSet cs2 = new ColumnSet(new string[] {"address1_city","address1_line1","address1_stateorprovince",
"name","industrycode"});
try
{
Account account = (Account)OrgService.Retrieve("account", new Guid(comboAccounts.SelectedValue.ToString()), cs2);
txtName.Text = account.Name;
txtCity.Text = account.Address1_City;
txtAddress.Text = account.Address1_Line1;
txtState.Text = account.Address1_StateOrProvince;
}
catch (Exception ex)
{
MessageBox.Show("An error happened: " + ex.Message);
}


Delete method is solely done by the organization service, so it didn't change due the style we use.



Method : Create



It almost the same, except we will use Account class and its properties instead of the Entity class and its attributes. Modify the btnSaveNew_Click event handler to look like:



try
{
Account account = new Account();
account.Name = txtName.Text;
account.Address1_Line1 = txtAddress.Text;
account.Address1_City = txtCity.Text;
account.Address1_StateOrProvince = txtState.Text;
OrgService.Create(account);
MessageBox.Show("Account created successfully");
}
catch (Exception ex)
{
MessageBox.Show("An error occurred : " + ex.Message);
}


This post is one of multiple posts to come under the same topic, Microsoft Dynamics CRM 2011 for Developers. Basicly we will deal with Dynamics CRM from the developer point of view. In this post we have tried to cover the basics of accessing Microsoft Dynamics CRM data using WCF. We tried the basic data operations: retrieve multiple records, retrieve one record, update, delete, and insert. We tried to cover both early-bounding and late-bounding approaches in our implementations.

Friday, December 2, 2011

JSON–yet another tutorial :)

What is JSON?

JSON (or JavaScript Object Notation) is a highly portable data interchange format. While its structure is recognized natively by Javascript (as it is Javascript), its formatting conventions are easily recognized by other C-like languages.

JSON is built on two structures:

  • A collection of name/value pairs. In various languages, this is realized as an object, record, struct, dictionary, hash table, keyed list, or associative array. Example:
var jason = {
"age" : "28",
"hometown" : "Cairo, Egypt",
"gender" : "male"
};

The object created in the example could be accessed like any other object.

  • An ordered list of values. In most languages, this is realized as an array, vector, list, or sequence. Example,
var family = [{
"name" : "Jason",
"age" : "24",
"gender" : "male"
},
{
"name" : "Kyle",
"age" : "21",
"gender" : "male"
}];

This array could be accessed like any array of objects.

Since JSON and XML are both used for data exchange, you may find yourself in the middle of deciding which format to use.

Reasons to choose JSON over XML
  1. JSON is easier to read than XML (especially of large amounts of data)
  2. JSON requires less tags than XML – XML items must be wrapped in open and close tags whereas JSON you just name the tag once
  3. Because JSON is transportation-independent, you can just bypass the XMLHttpRequest object for getting your data.
  4. JavaScript is not just data – you can also put methods and all sorts of goodies in JSON format.
  5. JSON is better at helping procedural decisions in your JavaScript based on objects and their values (or methods).
  6. You can get JSON data from anywhere, not just your own domain.
Reasons to choose XML over JSON
  1. Easy to take XML and apply XSLT to make XHTML.
  2. XML is supported by many more desktop applications than JSON.
  3. XML can put JSON in it on the way back to the client.
  4. AJAX includes XML in it and not JSON.

.Net Support for JSON

.Net framework provides System.Web.Script.Serialization.JavaScriptSerializer to serialize and deserialize objects. Here is a simple example:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace JSON_Demo1
{
public partial class Page1 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
Employee oEmployee1 = new Employee { Name = "Emp1", ID = "11", Age = "30" };
Employee oEmployee2 = new Employee { Name = "Emp2", ID = "22", Age = "31" };
Employee oEmployee3 = new Employee { Name = "Emp3", ID = "33", Age = "20" };
List oList = new List() { oEmployee1, oEmployee2, oEmployee3 };
System.Web.Script.Serialization.JavaScriptSerializer oSerializer = new System.Web.Script.Serialization.JavaScriptSerializer();
string sJSON = oSerializer.Serialize(oList);
Response.Write(sJSON);
}
}
public class Employee
{
public string Name { get; set; }
public string Age { get; set; }
public string ID { get; set; }
}
}

When you run the above application, you will see the JSON array on the response like so:

JSON_Demo11

Now let’s change this example a little bit so we can make Ajax call to get the JSON data and parse it using javaScript. Change the code-behind to look like:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.Services;

namespace JSON_Demo1
{
public partial class Page1 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
Response.Write(GetJSONData());
}

[WebMethod()]
public static string GetJSONData()
{
Employee oEmployee1 = new Employee { Name = "Emp1", ID = "11", Age = "30" };
Employee oEmployee2 = new Employee { Name = "Emp2", ID = "22", Age = "31" };
Employee oEmployee3 = new Employee { Name = "Emp3", ID = "33", Age = "20" };
List oList = new List() { oEmployee1, oEmployee2, oEmployee3 };
System.Web.Script.Serialization.JavaScriptSerializer oSerializer = new System.Web.Script.Serialization.JavaScriptSerializer();
return oSerializer.Serialize(oList);
}
}
public class Employee
{
public string Name { get; set; }
public string Age { get; set; }
public string ID { get; set; }
}

}

now change the .aspx page to look like:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Page1.aspx.cs" Inherits="JSON_Demo1.Page1" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function () {
$.ajax({
type: "POST",
url: "Page1.aspx/GetJSONData",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (msg) {
BuildTable(msg.d);
}
});
});

function BuildTable(msg) {
var table = '<table> <thead> <tr> <th>Name</th> <th>ID</th> <th>Age</th> </thead> <tbody>';
var myJSONObject = eval( msg );
for (var i = 0; i < 3; i++) {
var row = '<tr>';
row += '<td>' + myJSONObject[i].Name + '</td>';
row += '<td>' + myJSONObject[i].ID + '</td>';
row += '<td>' + myJSONObject[i].Age + '</td>';
row += '</tr>';
table += row;
}
table += '</tbody></table>';
$('#Container').html(table);
}
</script>
</head>
<body>
<div id="Container">
</div>
</body>
</html>


Now let’s run the application and see the output:



JSON_Demo12

In the previous example, we created a WebMethod, then call it from jQuery and pass the output of it to JavaScript method BuildTable(msg). This method convert the string msg into a JSON array of objects and then loop on that array to build the shown simple data table. We also rendered the JSON data to the browser directly from server-side code, just to show the original data and how it transformed using JSON.

In this post we gave a brief background about JSON, when use it and when use XML to send data, how .Net provides native serializer for JSON, and how to deserialize it using JavaScript. We may look into more advanced topics regarding JSON in future posts.

Good Luck

Tuesday, November 22, 2011

An introduction to Microsoft Message Queuing–Part 2

In the previous post, we explored very basic concepts of MSMQ. We used non-transactional queue to send and receive a message. In this post we will try to dive more into Message Queuing Queues.

Simply, queues are logical containers that Message Queuing uses to store and later forward messages, providing the bases for the loosely coupled aspects of Message Queuing. Queues can be created by applications and by Message Queuing. Queues created by applications or by users in an MMC snap-in are referred to as application queues. Queues created by Message Queuing are referred to as system-generated queues (we will talk about system- generated queues in another post).

Depending on the service provided by the queue, application queues can be public or private, and they can be transactional or nontransactional.

Application queues can play any of the following roles:

  • Destination queues : any queue used to send/receive messages between applications.
  • Administration queues : used for acknowledgment messages returned by Message Queuing or connector applications.
  • Response queues : used by receiving applications to return response messages to the sending application.
  • Report queues : used to store report messages returned by Message Queuing.
Destination Queues

Destination queues are any queue used to send/receive messages between applications. The sending application on computer 1 sends the messages to the queue and the receiving application on computer 2 reads the messages from the queue. Typically, destination queues are located on the same computer as the receiving application in order to minimize network traffic.

Public Versus Private Queues The decision to use public or private destination queues depends primarily on whether you want other applications to be able to locate the queues or not. Message Queuing registers private queues locally by storing a description of each queue in a separate file in the local queue storage (LQS) folder on the local computer (the default Lqs folder is %windir%\System32\MSMQ\Storage\Lqs). Also a description of each public queue created on the local computer is also stored locally in a separate file in the Lqs folder.

Adv. of Public Queues:

  • Registered in the directory service, so it can be located by other Message Queuing applications.
  • Persistent and its registration information can be backed up.

Adv. of Private Queues:

  • Requires minimal directory service overhead(faster to create, no latency, and no replication)
  • Can be created and deleted when the directory service is not working
  • Can be accessed directly by name without query the directory service.

Div. of Private Queues:

  • It is registered on local computer, so it is properties cannot be obtained by Message Queuing applications running on remote computers. Private queues can be exposed to other applications by making the location of the private queue known to the applications. To distribute the location of a private queue, an application can send the format name of the private queue as the response queue property of a message.

Transactional Versus Nontransactional Queues The decision to use transactional or nontransactional queues is based on whether the applications accessing the queue will be sending and receiving messages within the context of a transaction. So, what is a transaction ? a transaction is to execute a multiple-steps process such that either all or none of the steps will complete. In reality, transactions are handled by rolling back any steps that have already occurred if the entire transaction is not completed successfully.

When sending messages, only transactional queues can accept messages sent in the context of a transaction. These messages are also referred to as transactional messages. In a similar way, nontransactional queues can only accept messages sent outside the context of a transaction. Note that only transactional messages are delivered with exactly-once-delivery (EOD) guarantees.

When receiving messages, only local transactional queues can be accessed within the context of a transaction. The transactional queue must be local to the receiving application. On the other hand, nontransactional queues can be accessed within or outside of a transaction. Also, transactional queues, local or remote, can be accessed outside of a transaction (because we ask it to do less than what it can do).

If you just want to be able to recover lost messages, don’t use transactional queues. You can set the Recoverable property of a every message you sent. Or you can sent the queue property DefaultPropertiesToSend.Recoverable to true.

Creating a Transactional Queue
  • Through the snap in : just check the check-box Transactional below the queue name textbox.
  • Programmatically : just like privateQueue = MessageQueue.Create(".\\Private$\\privateQueue", true);

MessageQueue have a property called Transactional that you can check to ensure that the queue is transactional

MSMQ supports two types of transactions: Internal and External.

Internal Transactions

Class MessageQueueTransaction can be used to Begin(), Commit(), Abort() the transaction. It also can be passed through Send() and Receive() methods to that operation falls under a transaction. The class also exposes a Status property to give the transaction status. Transaction status can be one of:

  • Initialized : The transaction has been initialized but not yet started.
  • Pending : The transaction has been began but not committed or aborted yet.
  • Committed : The transaction has been committed.
  • Aborted : The transaction has been aborted.

Transaction Types when sending or receiving using MessageQueue class through transactional queues, you could pass one of the values in MessageQueueTransactionType enumeration. This specifies how you would like to interact with the queue. These values are:

  • Single : each queue operation will be doine in a separate internal transaction.
  • None : enable you to receive a message from a transactional queue, but outside a transaction. It also enables us to send a transactional message to a non-transactional queue.
  • Automatic : used with external transactions to direct the send or receive operations to use an already existing transaction context.

Now lets compile these pieces into one example to get sense of what internal transactional queues means.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Messaging;

namespace MSMQ_Demo3
{
class Program
{
static void Main(string[] args)
{
MessageQueueTransaction mqTran = new MessageQueueTransaction();
MessageQueue queueA = MessageQueue.Create(".\\Private$\\TranQueueA", true);
MessageQueue queueB = MessageQueue.Create(".\\Private$\\TranQueueB", true);
mqTran.Begin();
try
{
queueA.Send("Message A", "Label A", mqTran );
queueB.Send("Message B", "Label B", mqTran );
mqTran.Commit();
}
catch(Exception ex)
{
mqTran.Abort();
Console.WriteLine(ex.Message);
}

MessageQueue queueC = new MessageQueue(".\\Private$\\TranQueueA");
MessageQueue queueD = new MessageQueue(".\\Private$\\TranQueueB");
string strMsg = "";
mqTran.Begin();
try
{
Message msg = queueC.Receive(mqTran);
msg.Formatter = new XmlMessageFormatter(new Type[1] { typeof(string) });
strMsg = msg.Body.ToString();
msg = queueD.Receive(mqTran);
msg.Formatter = new XmlMessageFormatter(new Type[1] { typeof(string) });
strMsg += " \n ";
strMsg += msg.Body.ToString();
Console.WriteLine(strMsg);
mqTran.Commit();
}
catch (Exception ex)
{
mqTran.Abort();
Console.WriteLine(ex.Message);
}
Console.WriteLine();
}

}
}



In this example we created two transactional queues, send two messages to them. Then we received these messages. Both the sending and receiving done in a transaction that commits only after the success of all operations. If any errors happened, we abort the whole transaction and rollback all operations done in it.

In future posts we will talk more about MSQM details.

Thursday, November 17, 2011

An introduction to Microsoft Message Queuing

What is MSMQ ? Message Queuing (also known as MSMQ) is a messaging infrastructure and a development tool for creating distributed messaging applications for Microsoft Windows operating systems. Applications developed for Message Queuing send messages to queues, which are temporary storage locations, from which messages can proceed to their final destination as conditions permit.

Installing MSMQ The procedures to install MSMQ on Windows Server 2008, Winows Server 2008 R2, Windows 7, Windows Vista, Windows XP, and Windows Server 2003 are available here

Basic Messaging

MSMQ1

The image shows the basic messaging scenario. You have two applications: a sending application and a receiving application. A sending application prepares a message and puts it into a queue. A message can be any piece of information that the receiving application understands. The receiving application receives the message from the queue and processes it. One thing to note here is that the sender and the receiver are not tightly coupled and they can work without the other application being online.

Messaging in .Net To build a messaging application we need to create at least three components: queue, application to send messages, and another application to receive these messages.

Types of queues The basic types of MSMQ queues are: private and public. Public queues are those that are published in the active directory. So, applications running on different servers throughout the network can find and use public queues through the active directory. Private queues on the other hand are available locally on a particular machine and are not published in the active directory.

Creating a Queue Queues can be created either programmatically or through the computer management snap-in (if you installed MSMQ on your machine).

  • Programmatically The System.Messaging.MessageQueue class provides all the necessary functionality to work with and manipulate MSMQ queues. It is like a wrapper around message queuing. MessageQueue.Create(path) creates a non-transactional message queue at the specified path (we will talk about transactional and non-transactional queues later). For public queues, path is MachineName\QueueName. For private queues, MachineName\Private$\QueueName. You can use "." for the local computer. Code should look like:
MessageQueue privateQueue = MessageQueue.Create(".\\Private$\\privateQueue"); 




  • Through the computer management snap-in Open the computer management snap-in (right click computer, then manage). Navigate to Services and Applications, then Message Queuing. Right click on Private Queues –> New –> Private Queue. Or right click on public Queues –> New –> Public Queue.



MMC



Sending a message Use Send() method of your previously created MessageQueue object like so





privateQueue.Send("Message Body (could be any managed object)", "Message Label");



Receiving a message There are two types of operations with respect to reading a message fom the Queue: Peeking and Receiving. When we receive a message from the queue, the message is removed from the queue. Peeking is similar to Receiving but here the message is not removed from the queue. Code could look like





MessageQueue anotherPrivateQueue = new MessageQueue(".\\Private$\\privateQueue");


System.Messaging.Message msg = anotherPrivateQueue.Receive();



Additional Considerations before writing the first complete messaging application




  • You have to check if there is already a Message Queuing queue with the same name before creating your new queue. Use MessageQueue.Exists(path) to check for queue existence.


  • When receiving a message and before accessing its body, you have to set the Formatter property of the Message object. There is a lot of built-in formatters. For now, we can use XMLFormatter.



Now, let’s get things together into a “Hello, World” example. Open Visual Studio, New project, Windows forms. All reference to System.Messaging namespace. Then edit your code to look like so:





using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Messaging;

namespace MSMQ_Demo
{
class Program
{
static void Main(string[] args)
{
try
{
MessageQueue privateQueue;
if (!MessageQueue.Exists(".\\Private$\\privateQueue"))
privateQueue = MessageQueue.Create(".\\Private$\\privateQueue");
else
privateQueue = new MessageQueue(".\\Private$\\privateQueue");

privateQueue.Send("Hello, World !", "Message Label");
MessageQueue anotherPrivateQueue = new MessageQueue(".\\Private$\\privateQueue");
System.Messaging.Message msg = anotherPrivateQueue.Receive();
msg.Formatter = new System.Messaging.XmlMessageFormatter(new Type[1] { typeof(string) });
Console.WriteLine(msg.Body.ToString());
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
}



If you run the project, you will see a message-box displaying “Hello, World !”. This message content created by had been sent from MSMQ queue, received by another MSMQ, and processed. In our example both the sending and the receiving queues exist in the same application for the sake of simplicity. In real world applications they reside in very different areas.

This is a very basic introduction to MSMQ and non-transactional queues. In future posts, we will explore more advanced topics in MSMQ.

Friday, October 21, 2011

Asserts in NUnit

Assertions (or asserts for short) are helper methods that can assist us in determining whether a method under test is performing correctly or not. They let us assert conditions, data, and so on. All assertion methods will report failures (that’s when the assertion is false) or errors (that’s when we get an unexpected exception) and report these through the NUnit test runner. when a failure or error occurs, execution of the current test method is aborted. Other Test within the same test fixture will still be run.

Classic Asserts

  • Assert.AreEqual (expected, actual, string message)
    • For floating-point numbers we need to specify the tolerance of the equality.
    • Assert.AreEqual(3.33, 10.0/3.0, 0.01)  // Checks the result but looks only for the first two decimal places.
  • Assert.Less(x, y)     // asserts that x < y
  • Assert.Greater(x, y)      // asserts that x > y
  • Assert.LessOrEqual(x, y)    // asserts that x <= y
  • Assert.GreaterOrEqual(x, y)    // asserts that x >= y
  • Assert.IsNull(object, string message)
  • Assert.IsNotNull(object, string message)
  • Assert.AreSame(expected, actual, string message)
  • Assert.IsTrue(bool condition, string message)
  • Assert.IsFalse(bool condition, string message)
  • Assert.Fail(string message)
    • Fails the test immediately, can be used to mark sections of code that should not be reached.

*message in all previous statements is optional.

Constrain-Based Asserts

These are new assertion style introduced in NUnit 2.4. That new style enable many expectations to be evaluated together in a single assertion:

Assert.That(4, Is.LessThan(5) & Is.GreatThan(0));

  • Assert.That(actual, Is.EqualTo(expected))
  • Assert.That(actual, Is.Not.EqualTo(expected));
  • Assert.That(actual, Is.AtMost(expected));        //equivalent to Assert.LessOrEqual()
  • Assert.That(actual, Is.Atleast(expected));        //equivalent to Assert.GreaterOrEqual()
  • Assert.That(expected, Is.Null);
  • Assert.That(expected, Is.Not.Null);                 //equivalent to Assert.That(expected, !Is.Null);
  • Assert.That(expected, Is.Empty);                   //for collections and strings
  • Assert.That(actual, Is.InstanceOfType(expected));
  • Assert.That(actual, Has.Length(expected));
  • Assert.That(actualCollection, List.Contains(expectedValue));
    • Assert.That({5, 3, 2}, List.contains(2))   //will pass
  • Assert.That(actualCollection, Is.SubsetOf(expectedCollection));
    • Assert.That({5, 3, 2}, Is.SubsetOf({5, 4, 3, 2, 1})
  • Assert.That(actual, Text.StartsWith(expected)); //asserts that the expected string is at the beginning of actual
  • Assert.That(actual, Text.Matches(expected));    //asserts that the expected regular expression string matches actual
  • FileAssert.AreEqual(FileInfo expected, FileInfo actual);
    • FileAssert.AreEqual(String pathToExpected, String PathToActual);

NUnit and Exceptions

Part of your code behavior may be throwing a specific exception in certain cases. If you want to assert that your code throws the exceptions that it designed to throw, you need to tag your test method with attribute: [ExpectedException(typeof(ExpectedException))].

   1:  [TestFixture]


   2:  public class ImportListTest


   3:  {


   4:      [Test]


   5:      [ExpectedException(typeof(ArgumentNullException))]


   6:      public void NullList()


   7:      {


   8:          Class1.ImportList(null);


   9:      }


  10:  }



This test method in now expected to throw an exception [from the call to ImportList(null)]. If it doesn’t, the test will fail. If a different exception is thrown (even a superclass of the one specified), the test fails. The test passes only if the exact exception specified is thrown.



Temporarily ignoring tests



If you wrote the test code first and will start writing code incrementally (something like TDD), you may temporarily ignore tests that you still implementing the code required to pass them. You could just tag these tests with attribute [Ignore(“Optional Message”)] . NUnit will report that these tests were skipped and show a yellow bar in the GUI, so you won’t forget about it later.

Structuring unit tests in NUnit

Our goal in the previous post Introduction to NUnit, was just to introduce the unit testing using NUnit as simple as possible. Now it is the time to elaborate more on NUnit framework, structuring and organizing your test cases. If you examined the test code again:

   1:  using System;


   2:  using NUnit.Framework;


   3:  namespace ClassLibrary1


   4:  {


   5:      [TestFixture]


   6:      public class CmpTest


   7:      {


   8:          [Test]


   9:          public void LargestOf3()


  10:          {


  11:              int[] numbers = new int[] { 8, 9, 7 };


  12:              Assert.That(Cmp.Largest(numbers), Is.EqualTo(9));


  13:          }


  14:      }


  15:  }



The code is pretty straightforward. The using statement on line 2 brings in the necessary NUnit classes.



Next, we have the class definition on line 6: each class that contains tests must be annotated with a [TestFixture] attribute. The class have to be public, so the test runners can run it. The class must have a public, no-parameter constructor.



Finally, the test class contains individual methods annotated with [Test] attributes. Any public, parameterless method specified with a [Test] attribute will be run automatically by NUnit.



Structuring Unit Tests



As a good object-oriented design concept, a class should be focused on one responsibility and only one. This applies to test fixtures as well. Test fixtures should be focused on verifying behavior in a specific scenario. Its name should reflect this scenario. Tests inside that fixture should test different behaviors within this scenario. Tests should be organized around behaviors, not necessarily individual methods. To keep things readable and clear in the test runner output, favor putting fixture classes under a namespace that includes the name of the class that the fixture are testing.




   1:  namespace solutionName.Test.ShoppingCartTest


   2:  {


   3:      [TestFixture]


   4:      public class EmptyCartFixture


   5:      {


   6:          [Test]


   7:          public void OverallRateIsZero() { }


   8:      }


   9:  }



Categories



NUnit provides an easy way to mark and run individual test and fixtures by using categories. A category is just a name that we define. We can associate different test methods with one or more categories, that enable us to select which categories we want to exclude (or include) when running the tests. A category is specified as an attribute.




   1:  using System;


   2:  using NUnit.Framework;


   3:  namespace ClassLibrary1


   4:  {


   5:      [TestFixture]


   6:      public class CmpTest


   7:      {


   8:          [Test]


   9:          [Category("Short")]


  10:          public void LargestOf3()


  11:          {


  12:              int[] numbers = new int[] { 8, 9, 7 };


  13:              Assert.That(Cmp.Largest(numbers), Is.EqualTo(9));


  14:          }


  15:   


  16:          [Test]


  17:          [Category("Long")]


  18:          [Category("Fred")]


  19:          public void LargestOf3Alt()


  20:          {


  21:              int[] numbers = new int[3];


  22:              numbers[0] = 1;


  23:              numbers[1] = 1;


  24:              numbers[2] = 1;


  25:              Assert.That(Cmp.Largest(numbers), Is.EqualTo(1));


  26:          }


  27:   


  28:          [SetUp]


  29:          public void LargestOf3Alt2()


  30:          {


  31:              int[] numbers = new int[1];


  32:              numbers[0] = 0;


  33:              Assert.That(Cmp.Largest(numbers), Is.EqualTo(0));


  34:          }


  35:      }


  36:  }



In the GUI, if you excluded “Short” methods from run, only LargestOf3() will be selected and executed.



NUnit3



When categories are used, only the tests in the selected categories will be run. Those tests in categories that are not selected are not reported at all. If no category selected in the GUI, then all methods will be executed unless it is tagged with Explicit attribute. The Explicit attribute causes a test or test fixture to be ignored unless it is explicitly selected for running.



Per-Method Setup and Teardown  We should write our test in order that each test can run independently of other tests; this allows us to run any test at any time in any order. In order to accomplish that we may need to reset things between tests or clean up after a test has run. [Setup] and [TearDown] attributes are used for these tasks.



Per-Fixture Setup and Teardown  If we need to set something up or clean up after the entire test class has run, use [TestFixtureSetup] and [TestFixtureTearDown] for that.



Although setup and teardown methods generally come in pair, they don’t have to do so.



Suppose we need some sort of database connection for each test. Rather than duplicating code in each test method that connects to and disconnects from the database, we could use SetUp and TearDown methods. Since creating the initial connection to the database can be slow, we may want to do that only once before all the tests run by using TestFixtureSetUp.




   1:  [TestFixture]


   2:  public class DBTest


   3:  {


   4:      private SqlConnection dbConn;


   5:              


   6:      [TestFixtureSetUp]


   7:      public void PerFixtureSetup()


   8:      {


   9:          dbConn = new SqlConnection("ConnectionString");


  10:          dbConn.Open();


  11:      }


  12:   


  13:      [SetUp]


  14:      public void PerTestSetup()


  15:      {


  16:          //populate database with test data


  17:      }


  18:   


  19:      [TearDown]


  20:      public void PerTestTearDown()


  21:      {


  22:          // clean up database


  23:      }


  24:   


  25:      [TestFixtureTearDown]


  26:      public void PerFixtureTearDown()


  27:      {


  28:          dbConn.Close();


  29:          dbConn.Dispose();


  30:      }


  31:   


  32:      [Test]


  33:      public void AccountAccess()


  34:      {


  35:          // Uses dbConn


  36:      }


  37:   


  38:      [Test]


  39:      public void EmployeeAccess()


  40:      {


  41:          // Uses dbConn


  42:      }


  43:  }



In this example, here is the methods run sequence: PerFixtureSetup >> PerTestSetup >> AccountAccess >> PerTestTearDown >> PerFixtureTearDown >> PerFixtureSetup >> PerTestSetup >> EmployeeAccess >> PertestTearDown >> PerFixtureTearDown.



In this post we tried to elaborate more on the NUnit framework and how we structure and organize test cases in NUnit.