Showing posts with label C#. Show all posts
Showing posts with label C#. Show all posts

Tuesday, October 1, 2013

Issue with XSD element in ASP.Net when there is Inheritance

In one of my project I was consuming an web service which had some Inheritance where the parent Class is EmployeeProfile and the child Class is FieldEmployeeProfile. When I was calling a method returning Child Class object Array, I was not getting the Child Class specific Properties (not those inherited from Parent) set. Instead, I found a property in Parent Class called "Any' which is an Array of XMLElement and having the missing Child Object Property equivalent Name-Values in the XML element array.

I will try to explain the problem using a simpler example I created and the resolution.

Server Side Classes
    public class Shape
    {
        //[System.Xml.Serialization.XmlTypeAttribute("Name")]
        [System.Xml.Serialization.XmlElement(Order = 0)]
        public string Name { get; set; }

        [System.Xml.Serialization.XmlElement(Order = 1)]
        public virtual int Area { get; set; }

        [System.Xml.Serialization.XmlAnyElementAttribute(Order = 2)]
        public System.Xml.XmlElement[] AnyElement
        {
            get;
            set;
        }
    }

    public class Rectangle : Shape
    {
        [System.Xml.Serialization.XmlElement(Order = 0)]
        public int Side1 { get; set; }

        [System.Xml.Serialization.XmlElement(Order = 1)]
        public int Side2 { get; set; }

        [System.Xml.Serialization.XmlElement(Order = 2)]
        public override int Area
        {
            get
            {
                return Side1 * Side2;
            }
        }
        [System.Xml.Serialization.XmlAnyElement(Order = 3)]
        public System.Xml.XmlElement[] AnyChildElement
        {
            get;
            set;
        }
    }

Note the AnyElement in Parent Class and special attention to Order value. I will explain it later.

The WSDL generated for these classes as as below


<s:complexType name="Shape">
  <s:sequence>
    <s:element minOccurs="0" maxOccurs="1" name="Name" type="s:string" />
    <s:element minOccurs="1" maxOccurs="1" name="Area" type="s:int" />
    <s:any minOccurs="0" maxOccurs="unbounded" />
  </s:sequence>
</s:complexType>

<s:complexType name="Rectangle">
  <s:complexContent mixed="false">
    <s:extension base="tns:Shape">
      <s:sequence>
        <s:element minOccurs="1" maxOccurs="1" name="Side1" type="s:int" />
        <s:element minOccurs="1" maxOccurs="1" name="Side2" type="s:int" />
        <s:any minOccurs="0" maxOccurs="unbounded" />
      </s:sequence>
    </s:extension>
  </s:complexContent>
</s:complexType> 

When my web method returns Rectangle I get it as below with Side1 and Side2 property values as 0 and the base Any Property is having those missing property related XMLElements.



To fix this the easiest way is to remove the "Any" property related code from the Base Class shape in "Reference.Cs" file as below (you need to click on "Show All Files" in Solution explorer top to show Reference.cs file in solution explorer).

The alternate approach is to update the reference.cs file for the code generated for child class Rectangle as below:
[System.Xml.Serialization.XmlElementAttribute(Order = 0)]
        public int Side1
        {
            get
            {
                if (this.side1Field == 0)
                {
                    foreach (System.Xml.XmlElement xe in base.Any)
                    {
                        if (xe.Name == "Side1")
                        {
                            int.TryParse(xe.InnerText, out this.side1Field);
                        }
                    }
                }
                return this.side1Field;
            }
            set
            {
                this.side1Field = value;
            }
        }

        ///
        [System.Xml.Serialization.XmlElementAttribute(Order = 1)]
        public int Side2
        {
            get
            {
                if (this.side2Field == 0)
                {
                    foreach (System.Xml.XmlElement xe in base.Any)
                    {
                        if (xe.Name == "Side2")
                        {
                            int.TryParse(xe.InnerText, out this.side2Field);
                        }
                    }
                }
                return this.side2Field;
            }
            set
            {
                this.side2Field = value;
            }

        }

Note the tag is for expending the request & response payload for an web service in future without changing the WSDL. So you may require to actually utilize the Any property. So you shouldn't delete the property from reference.cs file if your code needs to handle any additional node without breaking it's logic.

I previously mentioned to pay special attention to Order value in the server side code for the classes. The reason is that all the properties following the Any element, will not be populated if you are not taking special care. It will have same null/0 value as the Child class properties.

Saturday, June 1, 2013

C# Predicate, Anonymous Delegate & Lambda Expression usage to get same result

Predicate:

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
    	List list = new List { 1, 2, 3 };

    	Predicate predicate = new Predicate(greaterThanTwo);

    	List newList = list.FindAll(predicate);
    }

    static bool greaterThanTwo(int arg)
    {
    	return arg > 2;
    }
}
 

Anonymous Delegate:

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        List list = new List { 1, 2, 3 };

        List newList = list.FindAll(delegate(int arg)
                           {
                               return arg> 2;
                           });
    }
}

Lambda Expression:

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
    	List list = new List { 1, 2, 3 };

    	List newList = list.FindAll(i => i > 2);
    }
} 
 
Reference 

Tuesday, October 13, 2009

Custom paging in Gridview With ObjectDataSource

Many times we use paging with GridView with AllowPaging = "True" and binding the GridView with some ObjectDataSource. It actually fetches all row from the database and depending on the no of records it fetched, it generates the Pager section of the page and according to the current page index, it shows the set of record.
This approach is good for when you have limited no of record in the database. But there are many situations where there is thousands of rows in the database and you have to display only 25 records(PageSize) out of that thousands of records. So it is not good practice to fetch all record through object datasource to display only 25 records.
Here we should use custom paging to fetch only the 25 rows starting from the startindex which is
CurrentPageIndex*PageSize (As Index is 0 Based).
Calculated automatically by objectdatasource.
Here is the change you have to do

  • Set EnablePaging="True" for ObjectDataSource

  • Set The SelectMethod Property

  • Set value for following Properties of ObjecDataSource StartRowIndexParameterName, SortParameterName, MaximumRowsParameterName
    These parameters needs to be present in the method attached for selecting the result for objectdatasource.

  • Set SelectCountMethod to the name of method returning the total no of rows.


Here is my ObjectDataSourceCode


<asp:objectdatasource id="objDS" runat="server" enablepaging="True" selectmethod="SearchResult" typename="PRP.BusinessLogic.TpilTblNsefaoscripmaster" startrowindexparametername="paramStartRowIndex" sortparametername="paramSortExpression" maximumrowsparametername="paramPageSize" selectcountmethod="GetNoOfRows">
<selectparameters>
<asp:parameter name="paramSymbol" type="String">
<asp:parameter direction="Output" name="paramTotalNoOfRows" type="Int32">
</asp:parameter>
</asp:parameter>
</selectparameters>
</asp:objectdatasource>


The SearchResult & GetNoOfRows Function


public DataTable SearchResult(string paramSymbol,
int paramStartRowIndex, int paramPageSize, string paramSortExpression, out int paramTotalNoOfRows)
{
TpilTblNsefaoscripmasterHelper.SearchResult(paramSymbol, paramStartRowIndex, paramStartRowIndex + paramPageSize, paramSortExpression, ref paramTotalNoOfRows);
this.totalNoOfRows = paramTotalNoOfRows;
}
int totalNoOfRows = 0;
public int GetNoOfRows(string paramSymbol,
int paramStartRowIndex, int paramPageSize, string paramSortExpression, out int paramTotalNoOfRows)
{
paramTotalNoOfRows = totalNoOfRows;
return totalNoOfRows;
}


The parameter list for both the functions are same but the second function retuns int no of rows. But i don't have used two function call for getting the total noofrows. Inside select function i have set the totalNoOfRows parameter which is accessed inside GetNoOfRows method to get the no of rows. This works as objectdatasource calls both the method on same object instance of the class and none of the methods and the class variable is static and the select methos is called first and then the row count method is called.
Now check the stored procedure used for this purpose


Create PROCEDURE [dbo].[USP_TPIL_tbl_NSEFAOScripSelectForSearch]
@Symbol varchar(50),
@StartIndex int = 0,
@EndIndex int =25,
@SortExpression varchar(50),
@TotalNoOfRows int OUTPUT
AS
SET NOCOUNT ON
Select * from
(
SELECT m.Instrument,m.Symbol,m.SymbolDescription,ExpiryDate,
Row_Number() OVER (Order By
CASE WHEN @SortExpression='EXPIRYDATE' OR @SortExpression='EXPIRYDATE ASC' THEN m.EXPIRYDATE END DESC,
CASE WHEN @SortExpression='EXPIRYDATE DESC' THEN m.EXPIRYDATE END ASC ,
CASE WHEN @SortExpression='SYMBOL' OR @SortExpression='SYMBOL ASC' THEN m.SYMBOL END DESC,
CASE WHEN @SortExpression='SYMBOL DESC' THEN m.SYMBOL END ASC
) as RowNumber
FROM
[dbo].[TPILl_NSEFAOScripMaster] m
WHERE
(m.[Symbol] LIKE @Symbol OR @Symbol = '')
)t
Where RowNumber>@StartIndex AND RowNumber<=@EndIndex --return SELECT @TotalNoOfRows = Count(*) FROM [dbo].[TPILl_NSEFAOScripMaster] m WHERE (m.[Symbol] LIKE @Symbol OR @Symbol = '')


As i am using Sql Server 2005, i used ROW_Number() function. The value of output parameter "TotalNoOfRows " is set to the variable "totalNoOfRows" inside "SearchResult" function.
To know about how to get Row Number in Sql Server 2000 please check the bottom of this link.

Wednesday, December 31, 2008

Paging,Sorting in datagrid

Paging and sorting is the most common feature of datagrid. As i am very much used to with ObjectDataSource, i don't have to do anything for implementing Paging and sorting.
Just set the datasource of the gridview to the ObjectDataSource and
set the AllowPaging and AllowSorting property of the grid view to true and
for each column put some SortExpression and
some pagesize for the gridview.
And thats all for implementing the paging and sorting. ObjectDataSource will take care of the remainings for you.
But some situalition arises where i must not use ObjectDataSource, actuaaly not using ObjectDataSource is easier from coding perspective though we have to implement the paging and sorting explicitly. So i used this code, a overloaded version of bindGrid() function to handle the situaltion

protected override void OnInit(EventArgs e)
{
base.OnInit(e);
gvStockCode.Sorting += new GridViewSortEventHandler(gvStockCode_Sorting);
gvStockCode.PageIndexChanging += new GridViewPageEventHandler(gvStockCode_PageIndexChanging);
}

void gvStockCode_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
gvStockCode.PageIndex = e.NewPageIndex;
bindGrid(); //Call bindgrid without any parameter so that previous sorting is maintained
}

void gvStockCode_Sorting(object sender, GridViewSortEventArgs e)
{
gvStockCode.PageIndex = 0; //Don't change page index if you want to show the old page the user was
if (ViewState["SortDirection"] != null && ViewState["SortExpression"] != null)
{

SortDirection direction = (SortDirection)ViewState["SortDirection"];
string sortExpr = ViewState["SortExpression"].ToString();
if (sortExpr.ToLower() == e.SortExpression.ToLower())
{
direction = direction == SortDirection.Ascending ? SortDirection.Descending : SortDirection.Ascending;
}
bindGrid(e.SortExpression, direction);
}
else
{
bindGrid(e.SortExpression, e.SortDirection);
}
}
protected void Page_Load(object sender, EventArgs e)
{
If(!IsPostBack)
bindGrid();
}
void bindGrid()
{
SortDirection direction = SortDirection.Ascending; //Default Sort Direction
string sortExpr = ""; //Default sort expression, you can put any expression if wanted to be default for grid
if (ViewState["SortDirection"] != null && ViewState["SortExpression"] != null)
{
direction = (SortDirection)ViewState["SortDirection"];
sortExpr = ViewState["SortExpression"].ToString();
}
bindGrid(sortExpr, direction);
}
void bindGrid(string sortExpression, SortDirection sortDirection)
{
DataTable dt = BusinessLogic.FillTable();//Some function declared in BL

DataView dv = new DataView(dt);
if (sortExpression != string.Empty)
{
if (sortDirection == SortDirection.Ascending)
dv.Sort = sortExpression + " ASC";
else
dv.Sort = sortExpression + " DESC";
}
gvStockCode.DataSource = dv;
gvStockCode.DataBind();
ViewState["SortExpression"] = sortExpression;
ViewState["SortDirection"] = sortDirection;
}

Thursday, October 30, 2008

Trigger validator control validation from javascript

function checkForConfirmRate()
{
for(var i=0;i<Page_Validators.length;i++)
{
if(Page_Validators[i].id != '<%= rfvStockCode.ClientID %>')
{
continue;
}
ValidatorValidate(Page_Validators[i]); //Function to trigger the validation
ValidatorUpdateIsValid();//To show the validation message according to the validator display property
ValidationSummaryOnSubmit();//To show in sumary(if exists)
return Page_IsValid;
}
}

Thursday, September 18, 2008

Run aggregate on datatable column

I had one table with columns "Name" and "Department" which i need to display in a multiline textbox. like below
Name~~~~~~~~ Dept
Tarun Ghosh~~~SWD
Diptangshu Das~SSWD
So that the names and Dept are aligned properly. So i needed the Max of the string length of the column "Name" and give a right-padding to name to make all of same length with the maximum lengthed name.
Firstly i went with the primitive looping through each record and calculate the max of the row, if it is greater than the global max, set global max to current max algo...
But i was not satisfied with the approach even though no problem.
Then i got the
public Object Compute(
string expression,
string filter
)
function of DataTable. Expression par needs to be some aggregate function lik Sum, Avg,Min,Max,Count,Var. with filter expression is same as where clause in dt.Select() function.
But one problemmmmmmmm.... The expression parameter can't work on computed column. Like say you have two column qty and unit price. You need to get the max(qty*unitPrice), then first you have to add a new column to hold the value of the multiplied result and then use the compute function on that column.
So in my case i wanted to get the max of length. So i added a column as

DataColumn col = new DataColumn("Length");
col.Expression = "Len(Name)";
col.DataType = typeof(int);
dt.Columns.Add(col);
object obj= dt.Compute("Max(Length)","");
Response.Write(obj.ToString());

obj is storing the max length value
Some useful link
Link1
Link2

Wednesday, May 21, 2008

XML writing problem.. Encoding Fixing

MemoryStream ms = new MemoryStream();
XmlTextWriter writer = new XmlTextWriter(ms, System.Text.ASCIIEncoding.UTF8);
writer.Indentation = 3;
writer.Formatting = Formatting.Indented;
writer.WriteProcessingInstruction("xml", "version=\"1.0\" encoding=\"utf-8\"");
writer.WriteStartElement("Report");
writer.WriteAttributeString("xmlns", null, "http://schemas.microsoft.com/sqlserver/reporting/2003/10/reportdefinition");//Writing namespace
writer.WriteAttributeString("xmlns", "rd", null, "http://schemas.microsoft.com/SQLServer/reporting/reportdesigner");//Writing namespace


Or You can use StringBuilder class object like below
StringBuilder sb = new StringBuilder();
StringWriter sw = new StringWriter(sb);