Friday, May 27, 2011

ASP.NET server side handler for Valums Ajax file upload ; file uploader supports multiple file upload with progress bar , drag-and-drop

This ajax uploader uses XHR for uploading multiple files with progress-bar in FF3.6+, Safari4+, Chrome and falls back to hidden iframe based upload in other browsers, providing good user experience everywhere. You can also see php demo in Valums site http://valums.com/ajax-upload/
The current implementation has server side handler for java, php and Perl. But does not exist Asp.net handler. Here I have implemented a Asp.net handler for ajax file upload that supports  IE, Firefox and Chrome.
Problem is IE use context.Request.Files[] for sending file to server. But Firefox and Chrome use Context.Request.InputStream. So in handler you need to check both for reading stream.
For Firefox and Chrome you get fileName from header like
String filename = HttpContext.Current.Request.Headers["X-File-Name"];
Code that work in Firefox and Chrome
//This work for Firefox and Chrome.
Stream inputStream = HttpContext.Current.Request.InputStream;
FileStream fileStream = new FileStream(mapPath + "\\" + filename, FileMode.OpenOrCreate);
inputStream.CopyTo(fileStream);
fileStream.Close();
context.Response.Write("{success:true, name:\"" + filename + "\", path:\"" + path + "/" + filename + "\"}");
But for IE you need to use
HttpPostedFile uploadedfile = context.Request.Files[0];
Code that work for IE browser :
HttpPostedFile uploadedfile = context.Request.Files[0];
filename = uploadedfile.FileName;
uploadedfile.SaveAs(mapPath + "\\" + filename);
context.Response.Write("{success:true, name:\"" + filename + "\", path:\"" + path + "/" + filename + "\"}");
Here the response is send as JSON string and you will get JSON object as response. you need to send {success:true} to make ajax upload understand that file upload is successful otherwise you can send false.

Complete code is:
public void ProcessRequest(HttpContext context)
      {
          const string path = "Capture/Images";
          String filename = HttpContext.Current.Request.Headers["X-File-Name"];
          if (string.IsNullOrEmpty(filename) && HttpContext.Current.Request.Files.Count <= 0)
          {
              context.Response.Write("{success:false}");
          }
          else
          {
              string mapPath = HttpContext.Current.Server.MapPath(path);
              if (Directory.Exists(mapPath) == false)
              {
                  Directory.CreateDirectory(mapPath);
              }
              if (filename == null)
              {
                  //This work for IE
                  try
                  {
                      HttpPostedFile uploadedfile = context.Request.Files[0];
                      filename = uploadedfile.FileName;
                      uploadedfile.SaveAs(mapPath + "\\" + filename);
                      context.Response.Write("{success:true, name:\"" + filename + "\", path:\"" + path + "/" + filename + "\"}");
                  }
                  catch (Exception)
                  {
                      context.Response.Write("{success:false}");
                  }
              }
              else
              {
                  //This work for Firefox and Chrome.
                  FileStream fileStream = new FileStream(mapPath + "\\" + filename, FileMode.OpenOrCreate);
                  try
                  {
                      Stream inputStream = HttpContext.Current.Request.InputStream;
                      inputStream.CopyTo(fileStream);
                      context.Response.Write("{success:true, name:\"" + filename + "\", path:\"" + path + "/" + filename + "\"}");
                  }
                  catch (Exception)
                  {
                      context.Response.Write("{success:false}");
                  }
                  finally
                  {
                      fileStream.Close();
                  }
              }
          }
      }

Complete solution is available in codeproject http://www.codeproject.com/KB/aspnet/AspNetHandlerAjaxUpload.aspx

Saturday, May 14, 2011

JQuery context menu items active/ deactivate for .NET TreeView

I was needed to give some functionality to .NET tree view for user so that user can add, edit, activate or deactivate node. Jquery context menu is very nice and give me functionality to customize context menu according to my requirement. My requirement was to make some items active based on image of treeview. .NET treeview use table structure. if the node contain is <td> wich id is ‘xyz_01’ then image <td> id will be ‘xyz_01i’ . Based on this I find the image element and according to source of image I have changed the active menu items on mousedown event. MouseDown event work before displaying jquery context menu. The code is given here.

Context menu div is

<ul id="myMenu" class="contextMenu"> 
<li class="copy"><a href="#add">Add</a></li>
<li class="edit"><a href="#edit">Edit</a></li>
<li class="inactive"><a href="#Inactive">Inactivate</a></li>
<li class="active"><a href="#Active">Activate</a></li>
<li class="quit separator"><a href="#cancel">Cancel</a></li>
</ul>



The mouse down code for activate and deactive element according to treeview image source.




$("#MyTreeDiv A").mousedown(function () { 
var itemId = $(this).attr('id');
var imageItemId = itemId + 'i';

var img = $('#' + imageItemId).children('img').first();
var s = $(img).attr('src');
if (s.indexOf('inactive') > -1) {
$('#myMenu').enableContextMenuItems('#Active');
$('#myMenu').disableContextMenuItems('#Inactive');
$('#myMenu').disableContextMenuItems('#add');
$('#myMenu').disableContextMenuItems('#edit');
}
else if (s.indexOf('active') > -1) {

$('#myMenu').disableContextMenuItems('#Active');
$('#myMenu').enableContextMenuItems('#Inactive');
$('#myMenu').enableContextMenuItems('#add');
$('#myMenu').enableContextMenuItems('#edit');
}

});

Tuesday, February 15, 2011

WPF: Textblock vertical alignment with given height

I was needed to set the alignment of textblock in center and also need to set height which is greater than normal textblock text height. But problem is when the text height is assigned then vertical alignment of textblock does not work. To solve this problem easy way to set padding so that the textblock text remain at center position. For that you need to measure the height of textblock before setting the custom height of textblock. After getting the desiredsize of textblock you can calculate the top padding of text in textblock. Then set the padding and custom height of textblock. This will solve the problem of making text position at center giving custom height.
textBlock.Measure(new Size(infiniteWidth, infiniteHeight));
var textBlockHeight = textBlock.DesiredSize.Height;
var textBlockTopPaddig = (CustomHeight - textBlockHeight)/2;
textBlock.Padding = new Thickness(0,textBlockTopPaddig,0,0);
textBlock.Height = CustomHeight;
 
XAML 
But if you want to set the custom height of TextBox from XAML then create a StackPanel and set the TextBlock inside that StackPanel. Instead of setting TextBlock height set the height of StackPanel and set StackPanel vertical alignment as VerticalAlignment.Center. So now textblock will be displayed in center of StackPanel. 

Friday, February 11, 2011

WPF : Getting Size of Text of a TextBlock or Richtext from code-behind without Rendering

We can not get actual size of a textblock without rendering. So for getting the size of TextBlock or RichText we need to call measure function of TextBlock / Richtext to get the the width and height which it would desired to occupy when it will render and you will get this from DesiredSize property after calling measure function.
TextBlock textBlock = new TextBlock();
textBlock.TextWrapping = TextWrapping.Wrap;
textBlock.Text = “Test data”;
textBlock.Measure(new Size(400, 500));
there the measure takes the size which is available size of container element. We can give it infinity size for measuring the size of text.
There also have another low-level .NET class for measuring the size of Text without creating TextBlock.And it is FormattedText class. Actually TextBlock internally use FormattedText for measuring the size of Text. For measuring text size we can create object of FormattedText like this.
string testString = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor";
                       // Create the initial formatted text string.
                       FormattedText formattedText = new FormattedText(
                           testString,
                           CultureInfo.GetCultureInfo("en-us"),
                           FlowDirection.LeftToRight,
                           new Typeface("Verdana"),
                           32,
                           Brushes.Black);
Here we have defined an object of FormattedText class which actually takes text as string, cultureinfo, direction, font type , size of text and media brush.
This return the same size as Measure function of text block.
But we can not measure the Rich text using FormattedText function as format of every Run (Paragraph) is different. So for that we need to extract the direction, font , size of text and brush for every run element. There have a nice article for getting FormattedText from FlowDocument of RichText object. http://www.wpfmentor.com/2009/01/how-to-transfer-rich-text-from.html.

Friday, January 14, 2011

Retrieving data as objects using Enterprise library 5.0 database application block


Enterprise library 5 provided new extension which is called Accessors. Accessors execute the given query with parameters mapping and parameter values and also transform the result using output mapper you specified.
accessor
There are two types of accessors. SprocAccessor for stored procedure and SqlStringAccessor for SQL string. The most interesting part of accessors is mapping.
Here I give example with SqlStringAccessor. Lets see an simple example of using CreateSqlAccessor.
public IEnumerable<Company> GetCompanies()
      {
          return _database.CreateSqlStringAccessor<Company>(GetCompaniesSQL());
      }
Here company is my created DTO and column definition match with properties of Company class. Here in this case I have not given any custom output mapper and it used default mapper which matches property name and type with column of database and returns me IEnumarable of Customer.
There are two types of output mapper. Row mapper which takes each rows and transform into object so that it returns sequence of these objects.Another one is Result set mappers, takes entire result set and generates  a complete object graph.
Now problem is, I have a column in my Company table “Action” which stores value as Integer but in our code this “Action” is defined as an Enum. So here default mapping is not possible and we need to define a custom row mapper for converting the type of int to Enum type. 
Database application block provides a MapBuilder that make it easy to create a custom output mapper. MapBuilder expose a method BuildAllProperties which creates default output mapping .  For details about output mapping you can see the MSDN article http://msdn.microsoft.com/en-us/library/ff664486(v=pandp.50).aspx.  Now lets see the implementation of row mapping for “Action” column.
public IRowMapper<Company> GetCompanyRowMapper()
        {
          return  MapBuilder<Company>.MapAllProperties().Map(m => m.Action).WithFunc(
                    rec => (CompanyAction)Enum.ToObject(typeof(CompanyAction), rec.GetInt32(rec.GetOrdinal("Action")))).
                    Build();
        }
When we call MappAllProperties ad it gives IMapBuilderContext and after calling build it create RowMapping. Here after getting IMapBuildContext the property “Action” of Company class is mapped with  a  delegate function which works on IDataRecord and convert the value to enum. Here database value 1 is converted with CompanyAction enum value. Now  the GetCompanies function will look like this.
public IEnumerable<Company> GetCompanies()
      {
          return _database.CreateSqlStringAccessor<Company>(GetCompaniesSQL(),
           GetCompanyRowMapper()).Execute();
      }
Accessors takes rowmapper as input and it returns all companies. But if I need to get a company with company Id only which will return a single company then I also have to give company id as input parameter and create a parameter mapping.
To create a custom parameter mapping I have implemented IParameterMapper interface and mapping is assigned inside AssignParameters method body.
private class CompanySelectParameterMapper : IParameterMapper
       {
           public void AssignParameters(DbCommand command, object[] parameterValues)
           {
               DbParameter parameter = null;
               parameter = command.CreateParameter();
               parameter.ParameterName = "@Id";
               parameter.Value = parameterValues[0];
               command.Parameters.Add(parameter);
           }
       }

Here it convert DbParameter for inputs and assign this to command. I have shown here simple implementation of this mapping.

So the function for getting a single company with company id is
public Company GetCompanyById(int id)
       {
           return _database.CreateSqlStringAccessor<Company>(GetCompanyById(), new CompanySelectParameterMapper(),GetCompanyRowMapper()).Execute(id).SingleOrDefault();
       }
Here you can see I have created an object of parameter mapper and in the Execute() function the values of parameters is defined. So the AssignParameter will be called when Accessor will call the Execute method and populate the command with parameter value.
Here you have seen how to retrieve data as object and how to define custom output and parameter mapping with Accessors. As it create default output row mapping so we do not need to give extra effort to create O/ R mapping all time. SprocAccessor also provide same sets of feature as SqlStringAccessor provides.

Monday, January 10, 2011

Fetching ASP.NET authenticated page with HTTPWebRequest


For some purposes we needed to fetch data from an authenticated page of asp.net. When I try to browse that page it go to the login page. In the login page there have user name and password field and want to login to the page clicking on submit button.
In this case when user type user name and password and submit then in server side there has code on button click handler to check user name and password. So for authenticating to the page using HTTPWebRequest we need to know how ASP.NET send event to submit click handler. ASP.NET page has two hidden variables understand from server-side which button is clicked.
<input type="hidden" name="__EVENTTARGET" id="__EVENTTARGET" value="" />
<input type="hidden" name="__EVENTARGUMENT" id="__EVENTARGUMENT" value="" />

And also when button is clicked then a javascript  function is called which set the name of the button in __EVENTTARGET and command argument in _EVENTARGUMENT




function __doPostBack(eventTarget, eventArgument) {
if (!theForm.onsubmit || (theForm.onsubmit() != false)) {
theForm.__EVENTTARGET.value = eventTarget;
theForm.__EVENTARGUMENT.value = eventArgument;
theForm.submit();
}
}

So if we set the __EVENTTARGET value as button name then in server side of ASP.NET page life cycle it it raise postback event and call the Button event with the argument. You can see the button argument to understand which event is set to __EVENTARGUMENT hidden variable. The page which we want to authenticate have nothing as command argument. so it go as empty string. So when we request data we have to send username, password, and also __EVENTARGET as button name and   __EVENTARGUMENT as empty string. Then it will call the Button event with user name and password.


Our used HTTP web request class looks like this




public WebPostRequest(string url, CookieContainer  cookieContainer) 
{
theRequest = (HttpWebRequest)WebRequest.Create(url);
theRequest.CookieContainer = cookieContainer;
theRequest.Method = "POST";
theQueryData = new ArrayList();
}
public void Add(string key, string value)
{
theQueryData.Add(String.Format("{0}={1}", key, HttpUtility.UrlEncode(value)));
}

Here you can see it create a request and set the cookie container with give cookie. As we are authenticating the page so authenticated session is stored in cookie. So we need to assign the cookie container were cookies will be stored so that sending the same cookie we can request other page which we want to actually request.


So for first time when we want to login to the page then the we create the request like




CookieContainer cookieContainer = new CookieContainer(); 
WebPostRequest myPost = new WebPostRequest(http://samplehost/sample/LoginAdmin.aspx, cookieContainer);
myPost.Add("LoginAdmin$UserName", "username");
myPost.Add("LoginAdmin$Password", "password");
myPost.Add("__EVENTTARGET", "LoginAdmin$SubmitButton");
myPost.Add("__EVENTARGUMENT", "");
myPost.GetResponse();

You can see here a cookie container is added and  trying to authenticate by calling LoginAdmin.aspx page adding query data . Now when we try to GetResponse with post request then it will fill the cookie information in the  cookie container . So next time we will send this cookie container for request and the site will treat me as authenticated user. So the response code here




public string GetResponse() 
{// Set the encoding type
theRequest.ContentType = "application/x-www-form-urlencoded";
// Build a string containing all the parameters
string Parameters = String.Join("&", (String[])theQueryData.ToArray(typeof(string)));
theRequest.ContentLength = Parameters.Length;
// We write the parameters into the request
StreamWriter sw = new StreamWriter(theRequest.GetRequestStream());
sw.Write(Parameters);
sw.Close();
// Execute the query
theResponse = (HttpWebResponse)theRequest.GetResponse();
StreamReader sr = new StreamReader(theResponse.GetResponseStream());
HttpStatusCode code = theResponse.StatusCode;
return sr.ReadToEnd();
}

from the response string you can understand that you have authenticated to the page.


But other target page was not the LoginAdmin.aspx. We called this page for authentication and also get authenticated cookie in our cookie container . So now we can send request again with then same cookie container to get the output of desired page.




myPost = new WebPostRequest("http://samplehost/sample/Targetpage.aspx", cookieContainer); 
myPost.Add("ctl00$cphPage$txtDate", "04/11/2010");
myPost.Add("__EVENTTARGET", "ctl00_cphPage_btnSend");
myPost.Add("__EVENTARGUMENT", "");
string FinalRespose = myPost.GetResponse();

So far I have discussed here how we can request a authenticated authenticated asp.net authenticated page using HTTPWebRequest to fetch data from code. After that we can do anything with the retrieved output.

Friday, December 31, 2010

Binary and Xml Serializable Dictionary

You can also see my codeproject article Both Xml and Binary Serializable Dictionary
I had a project where I needed to use binary serialization for deep copy and also needed Xml serialization for saving these into database.
Dictionary class is not by default xml serializable. For making it serializable we  need to implement a derived class implement interface IXmlSerializable. Also to get all functionality of Dictionary I have implemented that class from Dictionary class. The key type of Dictionary is string as I needed so I make it string for simplicity.
[XmlRoot("Dictionary")]
public class SerializableDictionary<VT>:Dictionary<string,VT>,IXmlSerializable


IXmlSerializable class contains following method that we needed to implement in our class


public interface IXmlSerializable
{
XmlSchema GetSchema();
void ReadXml(XmlReader reader);
void WriteXml(XmlWriter writer);
}   


But we also have to make our dictionary binary serializable. For serialization we need to set serializable attribute over our derived class. However when we try to deserialize our derived class in raise error saying there is no appropriate contractor to deserialize our class though default constructor exist. Dictionary<> class implements its own custom serialization using ISerializable so our derived class need special constructor for deserialization


public SerializableDictionary(SerializationInfo info, StreamingContext context):base(info,context)
        { 
        }





So the implementation of SeriliazableDictionary<T> which can be serializable as Xml and also in binary formate is given bellow.


[Serializable]
[XmlRoot("Dictionary")]


public class SerializableDictionary<VT>: Dictionary<string,VT>,IXmlSerializable
{ 
public SerializableDictionary( SerializationInfo info, StreamingContext context):base(info,context){} public SerializableDictionary(){} public XmlSchema GetSchema(){         return (null);       }
   public void ReadXml(XmlReader reader)    {      Boolean wasEmpty = reader.IsEmptyElement;      reader.Read();      if (wasEmpty)       {          return;       }      while (reader.NodeType!= XmlNodeType.EndElement)       {          if (reader.Name == "Item")           {            String key = reader.GetAttribute("Key");            Type type = Type.GetType(reader.GetAttribute("TypeName"));            reader.Read();            if (type != null)            {              Add(key, (VT)new XmlSerializer(type).Deserialize(reader));            }            else            {              reader.Skip();            }            reader.ReadEndElement();            reader.MoveToContent();           }        }        reader.ReadEndElement();   }   public void WriteXml(XmlWriter writer)   {    for (int i=0;i<Keys.Count;i++)    {      string key =Keys.ElementAt(i);      VT value= this.ElementAt(i).Value;      writer.WriteStartElement("Item");      writer.WriteAttributeString("Key", key);      writer.WriteAttributeString(string.Empty,"TypeName",string.Empty, value.GetType().AssemblyQualifiedName);      new XmlSerializer(value.GetType()).Serialize(writer, value);      writer.WriteEndElement();    }   } }