Sunday, July 29, 2012

Proper error handling in ASP.NET Web Forms


I want to show users two custom pages:
1) Error500.aspx -- for uncaught exceptions.
2) Error404.aspx -- for non-existing page.

The trick is that ASP.NET handles requests to *.aspx pages differently than to other types of pages.

Here's how I do it.

In Web.Config:

<system.web>
        <customErrors mode="RemoteOnly" defaultRedirect="~/Error.aspx" redirectMode="ResponseRewrite">
               <error statusCode="404" redirect="~/Error404.aspx"/>
               <error statusCode="500" redirect="~/Error500.aspx"/>
        customErrors>
system.web>

<system.webServer>
        <modules runAllManagedModulesForAllRequests="true">
               <add name=" PostJobFreeModule" type="PostJobFree.PostJobFreeModule" preCondition="managedHandler"/>
        modules>
        <httpErrors existingResponse="PassThrough" />
system.webServer>

In PostJobFreeModule.cs I use:
void application_EndRequest(object sender, EventArgs e)
{
        PageNotFoundHelper.ShowError404IfNeeded();
}

public static class PageNotFoundHelper
{
        public static void Set404StatusCode()
        {
                HttpContext.Current.Response.StatusCode = (int)System.Net.HttpStatusCode.NotFound;
               HttpContext.Current.Items["Set404StatusCode"] = true;
        }
 
        public static void ShowError404IfNeeded()
        {
               if (!HttpContext.Current.IsCustomErrorEnabled) return;
               if (HttpContext.Current.Response.StatusCode == 404)
               {
                       if (HttpContext.Current.Items["Set404StatusCode"] == null)
                       {
                               HttpContext.Current.Server.Transfer("~/Error404.aspx");
                       }
               }
        }
}

Thursday, July 26, 2012

Drop orphaned user who holds SQL Server service

It's easy to google "The database principal owns a schema in the database, and cannot be dropped" error, but have you tried to google "The database principal owns a service in the database, and cannot be dropped."?

I tried, and the results were miserable -- I could find only half-baked solutions.
In my case I restored SQL Server backup database that had service broker turned on and then tried to drop orphaned user... unsuccessfully as you can guess.

Here's the solution.

1) Run this query:
select
 'alter authorization on service::[' + name + '] to dbo;' as [SQL to execute prior to dropping user]
from sys.services
where principal_id = user_id('MyServer\MyOrphanedUser');
2) Execute SQL that you get as a result of the query above. It would look something like that:
alter authorization on service::[SqlQueryNotificationService-25509d9f-4171-4701-817f-834f79a4a882] to dbo;

3) Finally you can drop your orphaned user:
drop user [MyServer\MyOrphanedUser];

Credits: How to disconnect service from orphaned user by Nimit Parikh

P.S.: I also tried:
delete from sys.services where principal_id = user_id('MyServer\MyOrphanedUser')
and got: "Ad hoc updates to system catalogs are not allowed." error.

Thursday, May 19, 2011

Role-based permissions vs. Enterprise permissions

The problem


My application has multiple features. For example:
1) View resume.
2) Sending message to resume poster.
3) Viewing contact information on a resume.
My application has multiple users. For example:
1) Anonymous
2) Fred Lurker
3) Paul Generous
I want to allow some users to have access to one set of features and other users to have access to another set of features.
For example I want:
1) Anonymous users to have ability to view resume
2) Fred Lurker to be able to view resume and to send messages to resume poster.
3) Paul Generous to be able to see resume, send messages, and be able to see contact information on the resume.

Direct Permissions Mapping


The most direct approach would be to make every feature check a user who tries to access it. For example:
If (User is “Fred Lurker” or User is “Paul Generous”)
{
Allow user to send a message.
}
If (User is “Paul Generous”)
{
Allow user to view resume contact information.
}
That’s very direct and simple, but does not scale at all. My application has thousands of users, new users are added to the system, old users are deleted, and existing users are getting access more or less features over time. In order to deal with all that code would have to constantly change which is not feasible.

Role-based Permissions


Better approach would be to introduce roles. For example:
1) “Recruiters” role that has access to “Sending message to resume poster” feature.
2) “PayingUsers” role that has access to “Viewing contact information on a resume” feature.
Then:
1) Add “Fred Lurker” user to “Recruiters” role.
2) Add “Paul Generous” user to “PayingUsers” role.
With such approach software developers would define what roles have access to what features. They would define it in code (e.g. in C#, C++ or Java).
Application administrator would define roles that users have access to.
When Paul Generous pays his membership fee, administrator would simply add Paul to “PayingUsers” role. Administrator does not need to explicitly define what features Paul would have access to, because it’s already defined by developers in application code for “PayingUsers” role.
To summarize:
1) Roles introduce one intermediate step in mapping users to features.
2) Developers map roles to features
3) Administrators map users to roles.

Enterprise Permissions


What if I want my application to be more flexible and allow administrator to map groups of users to features without asking developers to modify code?
That could be setup like this:
1) My enterprise system would still have Users.
2) I’d add Groups, so administrator would be able to add users to groups.
3) Developer would add Privileges, so administrator would be able to map groups to privileges.
4) Developer would code features in such a way that one feature would be mapped to one privileges in my code:
If (user.HasPrivilege(“ViewResume”))
{
ShowResume()
}
5) Administrator would create and delete Groups and map these groups.
Enterprise Permissions system gives lots of flexibility to application administrators. It’s very appealing for IT department management to be able to tweak users’ permissions without need to wait for developers releasing new version of the app. That’s why such enterprise permissions systems are so popular.

Disadvantages of Enterprise Permissions


Unfortunately in real life flexible enterprise permissions system causes nothing but pain.
Here’s why:
1) With any flexibility comes added complexity.
Having “Users-Groups-Privileges-Features” chain instead of shorter “Users-Roles-Features” chain – significantly complicates the number of possible combinations of how permissions to access features can be granted to end users.
That means permissions could be granted to a user in several different ways through multiple groups. So it’s hard to revoke user’s permissions if necessary simply because it’s hard to figure out what permissions does the user really have.
2) It’s very hard for administrators to grasp what group should map to what privileges.
Administrator focuses on the end user. Administrator knows what groups user should belong to. But administrators have only vague idea about what privilege allows user to do in the application.
End result: developer is setting up the permissions anyway.
3) Enterprise permissions are much harder for developers.
Developers know what features should be available to what role (see Role-based Permissions above). Developers can map features to roles in their code.
Can developers map features to privileges and then map privileges to groups?
Yes, they can. But it’s harder. It’s more work. It requires both coding in C#/Java and scripting in SQL. Or even worse approach – mapping groups to privileges in the UI (error-prone deployment nightmare).
Administrators can setup new groups that developers do not know about. Administrators can delete groups that developers originally created. All that can quickly bring system to its knees. That’s why in the end administrators are afraid to create and delete groups and that defeats original purpose of enterprise system to give more flexibility to application administrators.
4) It’s hard to trace changes in Enterprise Permissions.
In role based system roles-features mapping is coded in C#/Java and is stored under source control. Code changes history helps to find out when and why this role was mapped to that feature.
Not so with mapping between groups and privileges. Such mapping is stored in database and is wiped out without trace every time when administrator changes the mapping.
There are no comments on why groups-features mapping was done the way it was done. There is simply no place to put such comment (unlike roles-features mapping that can be commented in C#/Java code).

Conclusion


The most robust way of handing permissions in most of applications is with role-based permissions (Users-Roles-Features).
In spite of “flexibility” appeal of enterprise-based permissions (Users-Groups-Privileges-Features), such system has serious disadvantages and virtually no real advantages.

Tuesday, January 25, 2011

Fixed headers scrollable content in HTML table

It's a tough problem to create HTML table in such a way that supports all of the following requirements simultaneously:
1) Has scrollable table body with content.
2) Has fixed table column headers.
3) Has header columns automatically aligned with body columns.

I looked through multiple solutions on the internet, and the best option so far is jquery.tablescroll.js plugin by Dimas Begunoff.

It allowed me:
1) Not to specify columns width explicitly.
2) Have multi-row headers with some cells spanning across several columns. The only trick is that first header row should have the same number of cells as body row.

While it's the best solution I could find -- it's still not perfect.
If table is pretty busy, and table content pushes column borders pretty hard -- header columns do not align perfectly with body columns.

If anybody knows better solution -- please let me know.

Monday, October 18, 2010

Boolean Search to SQL CONTAINS

Today I rolled out Boolean Search feature for PostJobFree.
PostJobFree uses SQL Server backend, so it seems obvious to use Full-Text search that SQL Server have to process boolean search queries from users.
Unfortunately it's not as easy:
Full-Text search CONTAINS query is pretty strict, and crashes the whole SELECT statement if CONTAINS clause syntax is not correct. For example:
asp sql
query would crash SQL Server's SELECT command if the query would be passed into CONTAINS clause as-is. Correct syntax would be:
asp AND sql
So I need to write a parser that parses user's search input into boolean search query object hierarchy and then renders CONTAINS query for SQL Server from that hierarchy.
Here's how I designed it.
Search object hierarchy consist of the following parts:
1) Word. It consists only of letters, digits, dots, and dashes. Dashes can be only be inside the word, between letters/digits. Dash outside the word is considered as negation.
2) Phrase. Phrase can have any chars wrapped in quotes.
3) OrList. OrList consists from two or more elements, separated by "or". For example:
("sql server" or oracle or DB2)
4) AndList. AndList consists from two or more elements, separated by "and" or "and not" operators. For example:
sql and asp and not oracle
This query would be rendered into AndList that consists of 3 elements.
Both OrList and AndList could consist not only from atomic pieces (such as Word and Phrase), but also from OrList and AndList subelements.

Parsing logic:
1) Split input query by quote char ('"'). Basically even elements in this split list are phrases. Everything else does not contain phrases.
2) After phrases are extracted, partially processed list consists of strings and Phrase objects.
3) Next step is to extract parenthesis that are not wrapped by other parentheses. Consider example:
(one and (two or three)) or four
"one and (two or three)" would be extracted from original query, and then recursively processed again.
The recursion ends when there are no more parentheses.
4) When recursion is so deep, that there are no parentheses left in a subquery, then that subquery is split by "or" word (or "|" char).
5) Last major step is to split remaining subquery into AndList. The trick here would be to appropriately assign negation if subquery was preceded by negation orerator "not", "!", or leading dash ("-").

After query is fully parsed, it's time to get final CONTAINS query for SQL Server.
It can be accomplished by overriding ToString() method for Word, Phrase, OrList, and AndList:
1) Word just converting containing text to UpperCase.
2) Phrase's ToString() overload converts InnerText to UpperCase and wraps it by quotes.
3) AndList joins all elements into single string using "&" separator or "&!" separator if one of AndList's subqueries was negated.
4) OrList joins all elements into single string using "|" separator. Then it wraps the result by parenthesis.

Thursday, September 23, 2010

How to set executionTimeout for individual requests?

You probably know that you can change http request processing timeout for specific page like this:
 <location path="MyLongRunningHttpHandler.ashx">
<system.web>
<httpRuntime executionTimeout="600" />
</system.web>
</location>
But what if you want to set it up for a control or just a function and do not have predefined list of pages to specify it in web.config?
Of maybe you don't want to pollute web.config with junk like that?

There should be some way to do it in C# code, right?
Right.
Here's how you do it:
    HttpContext.Current.Server.ScriptTimeout = 600; // 10 minutes
If that's what you were looking for, you probably want to test it.
I tried to test it too, and it turned out to be tricky.

First I set web.config's timeout to 2 seconds:
<httpRuntime executionTimeout="2" />

Then I put 10 seconds delay to my ashx handler's code-behind:
System.Threading.Thread.Sleep(10000); // 10 seconds

Then I commented this line:
// HttpContext.Current.Server.ScriptTimeout = 600; // 10 minutes

and opened my ashx handler's url in browser.

I expected it to crash with timeout error... but it did not happen.
:-O
Few experiments showed that executionTimeout works only if all of the following is true:
1) Domain name is not localhost (to test timeout you should use "YourComputerName" instead of "localhost").
2) Project is compiled in Release mode.
3) <compilation debug="false">
If any of the above is not true then executionTimeout length is virtually unlimited.
On top of that IIS typically times out later than executionTimeout limit asks it too.
When I set executionTimeout=2 and made my page request to sleep for 10 seconds, I was getting "Request timed out." response only in ~40% of requests.

Monday, September 13, 2010

Sneaky MaxItemsInObjectGraph attribute in WCF

I spent almost couple of days trying to figure out what caused WCF service to crash (in a weird way) when it was tried to return large resultset.
Initially the problem expressed itself on the WCF client side. When number of records in returning results was close to 5000 – WCF client generated
Meaningless "An existing connection was forcibly closed by the remote host." exception.
Google search for '"An existing connection was forcibly closed by the remote host." WCF size' brought up
WCF issues sending large data forum discussion.
The right answer (maxItemsInObjectGraph) was mentioned there, but it was buried under pile of misleading suggestions.

One step toward the solution was to use soapUI utility to make the requests (instead of calling WCF service from another .NET client).
That helped to determine that the problem is on the WCF server side -- soapUI simply couldn't get any response (when number of returning dataset rows was ~5000+).

What really helped to find the final answer -– was enabling WCF diagnostic by adding this to web.config on server side:
<system.diagnostics>
<sources>
<source name="System.ServiceModel" switchValue="Warning, ActivityTracing"
propagateActivity="true">
<listeners>
<add type="System.Diagnostics.DefaultTraceListener" name="Default">
<filter type="" />
</add>
<add name="ServiceModelTraceListener">
<filter type="" />
</add>
</listeners>
</source>
</sources>
<sharedListeners>
<add initializeData="app_tracelog.svclog"
type="System.Diagnostics.XmlWriterTraceListener, System, Version=2.0.0.0,
Culture=neutral, PublicKeyToken=b77a5c561934e089"
name="ServiceModelTraceListener" traceOutputOptions="Timestamp">
<filter type="" />
</add>
</sharedListeners>
</system.diagnostics>
Then app_tracelog.svclog revealed much more specific error message:
---
Maximum number of items that can be serialized or deserialized in an object graph is '65536'. Change the object graph or increase the MaxItemsInObjectGraph quota. '
---
Quick googling for "maxItemsInObjectGraph" brought me to MaxItemsInObjectGraph and keeping references when serializing in WCF blog post which recommended to add the following section to WCF server web.config:
<behaviors>
<serviceBehaviors>
<behavior name="LargeServiceBehavior">
<dataContractSerializer maxItemsInObjectGraph="100000"/>
</behavior>
</serviceBehaviors>
</behaviors>
and this section to WCF client web.config:
<behaviors>
<endpointBehaviors>
<behavior name="LargeEndpointBehavior">
<dataContractSerializer maxItemsInObjectGraph="100000"/>
</behavior>
</endpointBehaviors>
</behaviors>
That worked.
I used VS.NET 2008 / .NET Framework 3.5, but I think that is applicable to .NET 4.0 too.

Enjoy.

Thursday, June 03, 2010

How to preserve data during processing HttpRequest in ASP.NET?

The answer to it is HttpContext.Current.Items

I'm planning to use HttpContext.Current.Items for preserving pointers to controls that would render final javascript on the pages.
Or may be preserve javascript itself and then make these controls to retrieve the javascript from HttpContext.Current.Items["BottomScriptBuilder"] and HttpContext.Current.Items["HeadScriptBuilder"]?


System.Web.HttpContext.Current.Items is actually pretty old thing in ASP.NET

Sunday, May 16, 2010

How to include JavaScript tracking code into head control in asp.net

Google Analytics team recommends to include Asynchronous Google Analytics tracking javascript code right before closing </head> tag.
So, how to include that script into every page on your web site without modifying every page?

I considered multiple solutions:

1) Cut&paste into every page (the worst).

2) Create HeadScriptControl.cs server control and cut&paste it into every page (slightly better, but still requires lots of cut&paste).
Here's an example of HeadScriptControl code:
using System;
using System.Web.UI;
using System.Text;

public class HeadScriptControl : Control
{
private const string GoogleAnalyticsFirtsPartScript = @"
<script type=""text/javascript"">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-XXXXXX-2']);
_gaq.push(['_trackPageview']);
</script>
";
protected override void Render(HtmlTextWriter writer)
{
writer.Write(GoogleAnalyticsFirtsPartScript);
}
}

3) Create PageWithHeadScript.cs, inherit it from Page control, inherit every page on your web site from PageWithHeadScript.cs and render HeadScriptControl in PageWithHeadScript.cs like this:
public class PageWithHeadScript : Page
{
protected override void Render(HtmlTextWriter writer)
{
this.Header.Controls.Add(new HeadScriptControl());
base.Render(writer);
}
}
That approach requires even less cut&paste, but still every page on your web site needs to be touched.

4) Using HttpHandler.
I think that's the best approach, because it's not necessary to modify pages at all.
Here’s how I do it.

4.1. Create HttpModule:
public sealed class MyHttpModule : IHttpModule
{
void IHttpModule.Init(HttpApplication application)
{
application.PreRequestHandlerExecute += new EventHandler(application_PreRequestHandlerExecute);
}

void application_PreRequestHandlerExecute(object sender, EventArgs e)
{
RegisterPagePreRenderEventHandler();
}
private void RegisterPagePreRenderEventHandler()
{
if (HttpContext.Current.Handler.GetType().ToString().EndsWith("_aspx"))
{ // Register PreRender handler only on aspx pages.
Page page = (Page)HttpContext.Current.Handler;
page.PreRender += new EventHandler(page_PreRender);
}
}

void page_PreRender(object sender, EventArgs e)
{
System.Web.UI.Page page = (Page)sender;
page.Header.Controls.Add(new PostJobFree.WebUI.Controls.HeadScriptControl());
}

void Application_BeginRequest(object sender, EventArgs e)
{
DosAttackAnalyzer.AnalyzeHttpRequest(Ijs.Misc.BrowserIPAddress);
// DenyIpAddress.DenyAccessToCurrentIpAddressIfBlacklisted();
}
void IHttpModule.Dispose()
{
}
}

4.2. Register HttpModule in web.config:
<?xml version="1.0"?>
<configuration>
<system.webServer>
<modules>
<remove name="DenyIpAddressModule"/>
</modules>
</system.webServer>
</configuration>
</pre>

Note that it's impossible to add controls into page straight in PreRequestHandlerExecute event handler.
That's why I subscribe for Page.PreRender event.

Please let me know what you think.

ValidationSummary control is not red anymore

We upgraded PostJobFree.com to ASP.NET 4.0.
Then we discovered that ValidationSummary controls are not red anymore.

It turned out that The BaseValidator class and validation controls that derive from it no longer render red text by default.

Why did ASP.NET team make that breaking change?
Because they wanted to render cleaner and more CSS compliant HTML

Anyway, here's the solution:
Add ~/App_Themes/Default/Default.skin
Put there:
    <asp:ValidationSummary runat="server" ForeColor="Red" />


That worked for PostJobFree.
Hope it would help you too.

Saturday, May 15, 2010

ASP-NET-SQL-XML-Dennis-Gorelik-Resume


Dennis Gorelik
E-mail:
blogresume @ dennisgorelik.com

You describe your business problem – I deliver technical solution
Objective

Team Lead / Architect / Senior Software Developer for the position that requires deep technical knowledge as well as good understanding of underlying business processes.

Please ask me:
- How to deploy program changes without interruptions in web site work (which is 24/7 service).
- How to improve web site usability.
- How to use A/B testing in Google WebSite Optimizer.
- How to track web site performance and usage (Google Analytics, IIS Logs, custom logs, …).
- How to use Google AdSense and Google AdWords.
- How to integrate your solution with Google Checkout (payment system).
- How to add maps to your web site using Google Maps API.
- How ASP.NET Membership provider helps to keep users passwords reliably encrypted.
- Practical way to setup data exchange with other web sites using XML web services.
- How to quickly implement Full-Text search using SQL Server 2008.
- How to make Web Application and background Windows Service to communicate with each other using WCF.
- What physical tiers and logical layers I recommend to use for your application and why.
Background

Team Lead / Architect / Senior ASP.NET Developer. Over 10 years of experience in analysis, design and software development.
Full system life cycle experience: design, coding, testing, bug fixing, deployment, documentation and maintenance.
Preferences in Agile/RAD methodologies.
Technical skills

Languages: C# 4.0, VB.NET, T-SQL (DDL, DML), VB script, JavaScript, JQuery, HTML/DHTML, XML, ...

Technologies: ASP.NET 4.0, ADO.NET, WCF (Windows Communication Foundation), XML Web Services, Unit test, WPF …

Databases: MS SQL Server, Oracle, DB2 …
Development Tools: Google Search, Visual Studio.NET 2005 Team Edition, Microsoft SQL Server Management Studio, Nant, Toad VI, MS Visio, Google Docs, MS Office, Google Maps API.
Web Development: ASP.NET, XML Web Services, IIS, JavaScript, HTML, DHTML, CSS, ...
Reporting Tools: Microsoft Reporting Services, Crystal Reports.
Version and Source Control: TFS, Visual Source Safe, Subversion, VisualSVN, ...
Operating Systems: Windows 7, Windows Server 2008, MS Windows XP/2000/NT, Windows 95/98/Me, Windows 3.xx, MS DOS.
Projects history

May 2008 - Present. Team Lead, www.postjobfree.com, Jacksonville, FL

Tools and technologies: VS.NET 2010 (ASP.NET, WCF, AJAX, JQuery, Unit Tests, Web Tests, MembershipProvider …), C# 4.0, SQL Server 2008, VisualSVN, NDepend, Reflector, Google Analytics, AdWords, AdSense.

- Architected and implemented www.postjobfree.com.
- Integrated PostJobFree with external systems: job search aggregators, Google and search engines, Twitter, … (XML Services, API calls).
- Designed and lead implementation of search alerts, including immediate match delivery.
- Analyzed users’ feedback and prioritized development features.
- SEO (Search Engine Optimization):
- Implemented RESTful architecture: Made all content available through direct HTTP GET requests (direct URLs to every bit of information without need to clicking buttons (HTTP POST)).
- Exposed PostJobFree web content through Site Maps to Google and Yahoo search engines.
- Designed & implemented strategy to fight spam and duplicates.
- Designed database structure to accommodate business requirements.
September 2010 - December 2010. Senior ASP.NET developer, Lender Processing Services, Jacksonville, FL

http://www.lpsvcs.com - Tax Desktop application -- tax oriented component of Loan Processing System.
Tools & Technologies: ASP.NET 3.5, C#, VS.NET 2008, MS SQL Server 2008, T-SQL Stored Procedures, WCF web services, JavaScript, JQuery, TFS.
Accomplishments:
Extended business functionality (Loan details, Tax Lines).
Refactored spaghetti code into object oriented muti-tier/multi-layer solution with:
- DAO (Data Access Object -- client consuming WCF service)
- WCF service (Windows Communication Foundation)
- BLL (Business Logic Layer)
- DAL (Data Access Layer) that faces LINQ-to-SQL designer.
Eliminated the need of updating web references and minimized WCF client footprint in web.config, which improved code maintainability.
Identified SQL Connection leak and implemented solution that fixes it.

- September 2005 – May 2008. Senior ASP.NET & database developer, National Flood Services, Kalispell, MT
http://www.nfsmt.com/ - the company works in flood insurance business.
Conversion from Legacy system (AS-400/DB2/VB6/ASP/ASP.NET/MS SQL2000) to new ASP.NET 2005 / MS SQL 2005 application.

Tools & Technologies: ASP.NET 2.0, VS.NET 2005, C# 2.0, SSRS (SQL Server Reporting Services), Generics, Provider Model, User Controls, Master pages, GridView, Web parts, ADO.NET, Web Forms, XML Web Services, MS SQL Server 2000, Validation controls, JavaScript, Telerik controls, HTML/DHTML, CSS, VSS, Web Forms.

Achievements:

- Data Warehouse: Architected and developed system that imports data from legacy database (DB2) in form of flat files. Incoming data is parsed, scrubbed for errors, and loaded into final database in denormalized form for fast reports performance.

Data Correction Application: Designed and developed application that allows to review and fix incorrect data that was imported into Data Warehouse (Winforms, C#, Web Services, SQL Server 2005).

Insight Reports: Architected and developed web application for report requests – users can customize reports according to their requirements (ASP.NET 2.0, MS SQL 2005, SSRS (SQL Server Reporting Services), Web Services, JavaScript, HTML/DHTML, Telerik controls,
DB2, SQuirreL SQL 2.1).
- Developed custom Membership and Role providers to access legacy database (ASP.NET 2.0, Provider Model, MS SQL 2000, DB2).
- Developed custom localization provider (C# 2.0, Reflector. Namespaces: System.Reflection, System.Resources, System.Web.Compilation, System.IO).
Developed User Management system + Web site administration (MS SQL 2005, ASP.NET 2.0 Login controls).
- Developed several Flood Service providers (C# 2.0, HttpWebRequest).
- Developed UI for testing various Flood Service providers (ASP.NET, C# 2.0, GridView, ObjectDataSource, Session, ViewState).
- Helped others to solve technical problems.
June 2005 – August 2005. Senior ASP.NET developer, IBM Global Services, Indianapolis, IN

http://www.ibm.com/services/
This is fast paced project for Wells Fargo bank (http://www.wellsfargo.com/). The project was about making web portal for managing vendor evaluation scorecards.
Snapshots: http://www.dennisgorelik.com/resume/IbmGlobalServices
Tools & Technologies: ASP.NET, C#.NET, ASP.NET User Controls, ADO.NET, Web Forms, MS SQL Server 2000, Validation controls, JavaScript, HTML/DHTML, CSS, VSS, RapTier codegenerator.

Achievements:
- Analyzed business requirement.
- Defined technical details of the solution.
- Developed scorecard template functionality edit/view/report (ASP.NET, C#, MS SQL, Stored Procedures, RapTier, CSS, HTML).
- Implemented making and handling web-page snapshorts in “Web archive, single file (*.mht)” format:
- Developed functionality for saving web pages snapshots into database (used CDO functionality).
- Developed functionality for viewing saved snapshots.
Saved images into database and showed images from database on web pages.
Implemented Scorecard View with dynamical load of heterogeneous user controls into the web page.
Developed several appendices for Scorecard functionality:
- Designed database tables.
- Created stored Procedures / Views / User defined functions
- Created middle-tier DB classes (C#).
- Created AppendixControl_Base.cs as a base for “Appendix” user controls. This base class was used by me and other developers in the team.
- Created user controls (*.ascx / C#).
Tested, fixed, and modified application according to changes in user requirements.
December 2004 – June 2005. Senior ASP.NET developer, Cendant Mobility, Danbury, CT

http://www.cendantmobility.com/

Tools & Technologies: ASP.NET, C#.NET, ASP.NET User Controls, ADO.NET, Web Forms, Win Forms, MS SQL Server, Remoting, Validation controls, JavaScript, HTML/DHTML, CSS, Nant, VSS.
Analyzed business requirements.
- Developed Template Request module (ASP.NET, C#, JavaScript, ADO.NET) and integrated it with existing application https://atlas.cendantmobility.com/.
- Template finder.
- Multiple container pages.
- Various template list screens with "multiple rows add" and "multiple rows remove" functionality (ASP.NET, JavaScript). (“Template associations”, “Template list”).
- “Update” screens (document template update, package template update).
- Developed ASP.NET User controls, including:
- Template list ASP user control - with Middle tier call, page navigation (paging), and sorting all columns.
- Navigation ASP user control.
- Created unit tests (WinForms).
- Used the following techniques:
- Nested pages (iframe), including nesting iFrames.
- Popup pages (Template finder, Product selection)
- Style sheets (*.css)
- Wrote stored procedures.
- Set up Nant --- tool for automatic build generation (for daily build).
- Helped other developers to solve technical problems.

August 2004 – December 2004. Senior ASP.NET developer, MPS Group, Jacksonville, FL
http://www.mpsgroup.com/
“Knowledge Spring” web portal project development.
Developed portlets(ASP.NET user controls) for multi-tier web system.
Tools & Technologies: VS.NET, ASP.NET, User Controls, Portlets, Repeater, DataList, Validator Controls, JavaScript, C#.NET, VB.NET, WebForms, WinForms, Oracle 9.2, LLBLGen Pr- Engine, Toad VI, SQL Plus, VB Script, PL/SQL script, ADO.NET, XML Web Services, MS VSS 6.0d, ComponentArt TreeView.

Projects:
- Directory Browser (recursive browsing through database items + Properties PopUp)
- MessageSet Editor & Message Editor (used repeater and Cute Editor control)
- Role Editor, UserSelectionControl, Actions Editor PopUp
- Attribute Editor, Portlet type editor, User Control editor, Item Types editor, DomainMappings editor, Audiences editor, Actions editor (repeater, JavaScript including passing data between main and popup windows, Web Validation Controls)
- SubstitutionVariables editor (used RegEx expressions)
- FileReportViewer (including NTFS permissions check through Advapi32.dll and Kernel32.dll API)
- Developed Windows services (C#).
- Developed win forms test app.
- Site Directory View 3-layers tree (ComponentArt TreeView).
- Configurations loading (VB Script, PL/SQL script, *.lst files).
May 2004 – July 2004. .NET architect, Yellow Pepper, Boston, MA

http://www.yellowpepper.com/
Tools & Technologies: VS.NET, ASP.NET, C#.NET, VB.NET, WebForms, WinForms, MS SQL 2000, ADO.NET, XML Web Services, MS Visual Source Safe, Groove.

Projects:
- Shazam web service wrapper.
- SMS Tracker – tracks information about SMS messages delivery.
- SMS Games – games based on sending/receiving SMS text messages to/from cell phone.
- Phone number look up – look up information about specified phone number (Carrier, Gate, IsWireless, City, State, Country, Switch).
August 2003 – April 2004. Senior .Net Software developer, Wurzburg, Memphis, TN

Tools & Technologies: ASP.NET, C#.NET, WebForms, WinForms, MS SQL 2000, ADO.NET, Microsoft Application Block, Remoting, Crystal Reports, XML Web Services, User controls, Server Controls, MS Visual Source Safe, MS Project, MS Visio.

Projects:
Development of various functionalities for warehouse project.

Web-site security
Designed and developed security framework for the web application: User authentication and authorization, Cross-applications calls.

UPS address validation project
Designed and developed mail address validation program. The program interface is exposed through web-page interface (and .csv file) and through XML Web Service (http://www.wurzburg.com/UPS/UpsValidation.asmx).
Technologies: ASP.NET, IIS, C#, XML, XML Web Services.
The program prepares XML-request and send it to UPS.

The program is based on UPS EDI functionality exposed here:
https://www.ups.com/ups.app/xml/AV

Reports project
Developed various business reports. Reports are provided in PDF-format, HTML-format, and can be printed directly to the specified printer. Reports functionality is exposed as to end users (through web-pages) as to other developers (in form of XML web services).
Technologies: IIS, ASP.NET, C#, Crystal Reports, ADO.NET, MS SQL Server 2000 (stored procedures, views, functions), XML Web Services, IE 6.

Catalogue project
Designed catalogue module, including ASP.NET and MS SQL database design. Developed shopping card functionality.

Label printing project
Designed and developed program to print bar-code labels. Program is tightly integrated with the company’s database. For instance, user which prints a label is associated with it’s own label printer.
Technologies: IIS, ASP.NET, C#, Crystal Reports, ADO.NET, MS SQL Server 2000 (stored procedures, views, functions), IE 6.

Deployment
Worked out fast and reliable deployment method. This method allows to deploy development changes to Production every day. Automated deployment SQL-script preparation.
In case of emergency deployment can be made even more often (in extreme cases up to 4 times per day).
Technologies: VS.NET, Database project, VSS, ASP.NET.
Performance
After initial prototyping and user evaluation I improved performance of "bottle-neck" applications. Modified SQL-queries, used MS SQL Query analyzer and SQL Profiler.

Other responsibilities
Was responsible for managing project documentation and for Visual Source Safe administration.

April 2003 – August 2003. Team leader. Global Consulting Group, Cincinnati, OH

Tools & Technologies: Visual Studio .NET, VB.NET, C#.NET, WebForms, WinForms, ADO.NET, MS SQL 2000, MS Visual Source Safe, MS Project, MS Visio.

Responsibilities: Lead team of 3 developers.
Achievements:

- Analyzed business requirements.
- Designed application architecture.
- Wrote technical specification.
Coached team members.
- Implemented logical and physical database design.
- Created SQL-queries (T-SQL).
- Developed web UI forms (ASP.NET, WebForms).
- Implemented data exchange (ADO.NET).
- Created business components (C#.NET).
- Created reports (Crystal Reports 9.0).
- Created XML Web services.
- Created XSL transformations.
May 2002 - April 2003. Application Developer, Scala

http://www.scala.net/
Tools & Technologies:

Visual Studio.NET, VB.NET, ASP.NET, WinForm, WebForms, Visual Basic 6.0, MS XML Parser, SOAP, Crystal Reports, MS SQL Server, Oracle, VC++, VB Script, Syncr- VSS, Source of Site and Visual Source Safe for version control.
MS Project for time tracking.
Benjamin (http://benjamin.scala.se/) - for tracking bugs and features.
MS Office, Rational Rose diagrams – for documentation purposes.

Responsibilities: Migration of legacy VB6 application into new .NET application. Reports development, XML services development for ERP (Enterprise Resource Planning) system. Retail sales, Warehousing, and Accounting modules development.

Achievements:
- Converted existing VB6 application into VB.NET application.
- Developed WinForms (VB.NET).
- Developed WebForms (ASP.NET).
- Implemented business logic (VB.NET).
- Created and modified SQL-queries.
- Developed several XML services for iScala (see: http://www.scala.net/scalasap/scalasap.asp):
- Created XSD, XDR schemas and XML samples. (Used XML Spy http://www.xmlspy.com/).
- Created XSLT transformations. Used Xselerator http://www.vbxml.com/xselerator/.
- Created business reports (Crystal Reports).
- Created and maintained tools for development process:
- Universal AutoTest program for testing iScala XML-services.
- Wrote documentation for AutoTest program.
- XML validator – allows quick checking is XML document valid or not.
- XML service registrator – copies all necessary components of specified XML service on tester’s computer and registers them under COM+ server.
- Created and modified type libraries (*.idl, *.tlb).
- Designed Work Flow diagrams for iScala.
October 2001 - April 2002: System analyst/Software developer, Egar Technology Corporation

http://www.egartech.com/
Tools & Technologies: MS SQL 2000, VB 6.0, Data Environment, ADO, Far Point Spread 2.5 (data grid), Crystal Reports 8.0, VSS 6.0, Visual InterDev 6.0, ASP, Rational ClearQuest and MS Outlook.

Responsibilities:
Development of the Collateral module for financial system. Data Modeling. ER-diagrams (ERwin).
Full Application consists of more than 300 database tables, 200 views, 500 stored procedures, 1000 VB-forms and modules

Achievements:
- Developed Back End of the Collateral module (tables, constraints, views and stored procedures).
- Developed VB user interface (Designed client forms and wrote VB-code).
- Created various financial reports (Crystal Reports 8.0).
- Developed Web interface (ASP).
- Wrote SQL-script for database deployment on customer computer.
- Used Rational ClearQuest to track defects and change requests.
- Used Visual InterDev for DB-scripts (SP and view) handle and version tracking and control via VSS.
November 2000 – September 2001: Software developer, Granat International Inc., Cleveland, OH

http://www.granatinternational.com/
Tools & Technologies:
VB 6.0, MTS, Visual Source Safe 6.0, InterDev, IIS, ADO, MS SQL 7.0 (MS SQL Query Analyzer, MS SQL Enterprise manager), Microsoft Transaction Server 2.0, Crystal Reports 8.0, VB-script (MS-Word 2000), Windows 2000.

Project: Loan Inventory Control System. Migration from Clipper to VB6.
Application consists of more than 200 forms and reports. It is 3-tier application.

Responsibilities:
The task was complete transferring the business logic from the existing file-server application (AS400, Clipper) to the Windows 3-tier architecture. Customer is the “Leader Mortgage” co., USA, OH (http://www.mortgagemag.com/guide/c008/c008630.htm).

Achievements:
- Investigated behavior of DOS-application and its source code (Clipper).
- Created DTS-package for conversion *.dbf into MS SQL database.
- Developed SQL-queries and business logic (COM+ components).
- Created reports (Crystal Reports 8) and forms for view and update database information.
- Developed VB-script (MS Word 2000), which helps to convert large fragments of clipper source code to VB code.
- Developed Web interface (ASP).
Certification

Microsoft

http://www.microsoft.com/learning/mcp/transcripts
Transcript ID: 663106
Access Code: dennisgorelik
- 070-320 exam (Developing XML Web Services and Server Components with Microsoft Visual C#.NET and the Microsoft .NET Framework).
Score: 981.
- 080-316 exam (Developing and Implementing Windows-based Applications with Microsoft Visual C#.NET and Microsoft Visual Studio.NET).
Score: 917.
- 080-315 exam (Developing and Implementing Web Applications with Microsoft Visual C#.NET and Microsoft Visual Studio.NET).
Score: 916.
Brainbench

- 2004 Brainbench certification ASP.NET.
- 2004 Brainbench certification C#.NET.
- 2004 Brainbench certification VB.NET.
http://www.dennisgorelik.com/resume/BrainbenchNetCertification.htm
- 2000 Brainbench certification in MS SQL 7.0.
- 2000 Brainbench certification in VB 6.0.
- 2000 Brainbench certification in Active Server Pages (ASP).
- 2000 Brainbench certification in MS Visual Interdev 6.0.
Education

1997 - 2000 MS degree in Economic and Management. South-Ural State University, Chelyabinsk, Russia.
1991 - 1997 MS degree in Automatic Control Systems. Chelyabinsk State Technical University, Chelyabinsk, Russia.
Personal

Excellent analytical, problem solving, technical, interpersonal and communication skills with a strong entrepreneurial drive.
References

Wurzburg

Keywords
ASP.NET, C#, SQL, MS SQL Server, Microsoft SQL Server, Visual Basic, VB, JavaScript, JQuery, Microsoft developer, Microsoft technologies, Visual Studio 6.0, Visual Studio.NET, VC++, XML, MS XML Parser, XML services, XML Web Services, SOAP, EDI (Electronic Data Interchange), BizTalk, XSLT, XPath, XSD schemas, XDR schemas, OAGIS, Active Server Pages, ASPX, Visual InterDev, Visual Source Safe, VSS, VSS 6.0d, IIS, Internet Information Server, MS Office, Microsoft Office, Perl, Microsoft Access, Microsoft Word VBA, Microsoft Excel VBA, Outlook VBA, Windows 2000, Windows XP, Windows NT, Windows 98, Windows 95, Object Orienting Programming, OOP, Component Object Model, COM, COM+ Server, MTS Server, RDBMS, UML, Rational Rose, Rational ClearQuest, Crystal Reports 9.0, MSDN Library, AS400, XML Spy, ERP, Microsoft Office VBA, Microsoft Query Analyzer, Microsoft Enterprise Manager, Profiler, XSelerator, OAGIS, *.idl, *.tlb, mIDL, DLL, VB6, VB.NET, ASP.NET, User controls, Server Controls, Portlets, Repeater, DataList, DataGrid, Components, ActiveX controls, ADO, OLE DB, MS Project, MS Visio, Work Flow diagrams, The Far manager, The Bat, Grid, True DB grid, FarPoint Spread, MSN, ICQ, Email, VB script, Java script, HTML, DHTML, programmer, data modeling, ER-diagrams, Erwin, Database technologies, Database developer, System Analyst, DBA, stored procedures, SP, Views, Triggers, MS IE, eCommerce, Microsoft Internet Explorer, MCAD, NTFS permissions check, Oracle 9.2, Toad VI, SQL Plus, ComponentArt TreeView, LLBLGet, RapTier codegenerator, mht, CDO, WCF, WPF.

Willing to relocate to: Tampa, FL; Saint Petersburg, FL; Orlando, FL; Jacksonville, FL; Miami, FL; Atlanta, GA; Dallas, TX; Houston, TX; Austin, TX; San Antonio, TX; Raleigh, NC; Memphis, TN; Chattanooga, TN; Nashville, TN, Phoenix, AZ; Kansas, KS; San Diego, CA; San Francisco, CA; Oakland, CA, Los Angeles, CA; Orange County, CA; SC; AL; LA; CO; AR; MS; NM; OK and some other warm places.

Tuesday, April 13, 2010

Extreme intellisense

Scott Guthrie's team is working on technology that allows to build intellisense based on executing underlying JavaScript code.
It's not available in Visual Studio yet, but looks like it would be available soon.

Sunday, April 11, 2010

Cast from float to double error

I was surprised to find out that this line of code fails:

Assert.AreEqual(0.1d, (double)0.1f);

(double)0.1f is actually the same as ... drumbeat ... 0.100000001490116

Why does it happen?
Because float and double do NOT represent fractions precisely.
Rounding is always going on.

How to deal with this?
There are several options:
1) Round double after converting float number into it.
For example:

float f = 0.1f;
double d = Math.Round(f, 8);
would assign 0.1d to d.

2) Don't use float/Single and use double only.

double d = 0.1;
would assign exactly 0.1d to d.

3) Use decimal or bigdecimal if you are dealing with money.

decimal m = 0.1m

Hope it helps.

Saturday, January 23, 2010

ASP.NET: MVC Framework vs Web Forms Framework

It looks like "MVC vs Web Forms" debate heats up.

Here's my take on it:
1) Last time I checked, MVC required 50+% overhead (relative to Web Forms) in terms of the amount of code required to implement the same functionality.
Was that fundamental problem fixed yet?

Let's consider an example of business requirements:
Create a page that allows user enter text, click "Save" button, and then call existing business layer method BusinessLayer.Save().
With Web Forms approach it would take:
- 1 line of ASPX code for textbox
- 1 line of ASPX code for Save button (including Save_Click() call).
- 3 lines of code-behind:
void Save_Click() {
BusinessLayer.Save(Input.Text);
}
Total: 5 lines of code.

How many lines of code that task would get in MVC?

2) Now about why it's important to minimize number of lines of code:
Lines of code is the best available metric of project complexity.
Yes I know that different lines have different complexity attached to it, but by default I assume that complexity of Web Forms’ line is about the same as complexity of MVC's line of code.

3) Many developers say that it's good to know MVC even if you don't use it (just to be familiar with available options to be ready to jump on it).
I agree. Sort of.
The trick is to know what to learn. There are so many technologies out there so it's not possible to learn them all.
How do I know that MVC would have good return on my time invested?
I don't know it yet. Many developers are passionate about MVC, but relying just on buzz around new technology methodology is too risky: for example, RUP (Rational Unified Process) is nowhere now after all that buzz 10 years ago. Learning it (aside of the most basic concepts) would be mostly waste of time.
And lines of code overhead really kills my enthusiasm about MVC.

I'm open to change my mind though. Especially considering that MVC is getting more mature every year.

See also: Scott Guthrie chimed in with great "About Technical Debate" post and even better follow up comments about advantages of Web Forms vs Advantages of MVC Framework

-

Saturday, September 26, 2009

Unable to obtain public key for StrongNameKeyPair

You are using Visual Studio 2008 (SP1 or not -- doesn't matter).
You have test project that is signed with strong key and that strong key has a password on it.
You are trying to create a unit test for private method and are trying to create accessor.
You have an error like that:
"Creation of the private accessor for Xyz failed"

You have that error because you excluded "Test References" folder and YourProject.accessor file from your test project.

The reason why you excluded YourProject.accessor file from your project is that you were getting a compilation error:
"Unable to obtain public key for StrongNameKeyPair".

The reason why you are getting that error is that VS 2008 SP1 and even VS 2010 Beta 1 have a bug.

Workaround for that bug is to turn off strong key signing on your test project.

Read more here:
Unable to obtain public key for StrongNameKeyPair

Friday, May 29, 2009

SQL_Latin1_General_Cp850_BIN

While working on Auto-Moderator for PostJobFree.com I encountered the following problem: my C# code considered ‘3’ and ‘3’ as different words, but SQL Server considered them the same.
That expressed itself in the following error:
Cannot insert duplicate key row in object 'dbo.Word' with unique index 'IX_Word'.

That was a little bit surprising, considering that I defined Word as Unicode column (nvarchar).

While searching for the solution, my first thought was to make 'IX_Word' index not unique. That worked, but would have introduced other problems with spam filtering business logic down the road.

The solution should have been about making SQL Server to compare strings exactly the same way C# code does.

I started to look into SQL Server Collations, and finally found the solution: use SQL_Latin1_General_Cp850_BIN collation.

Basically the solution is about to declaring 'Word' column with SQL_Latin1_General_Cp850_BIN collation:
Create Table Word(
WordId bigint identity(1,1) not null,
Word nvarchar(50) COLLATE SQL_Latin1_General_Cp850_BIN not null,
JobPostCount int not null DEFAULT 0,
JobLogSpamCount int not null DEFAULT 0,
CreateDate datetime not null,
UpdateDate datetime not null,
CONSTRAINT PK_Word Primary Key Clustered
(
WordId ASC
)
)
GO

Create Unique Index IX_Word ON Word
(
Word
)
GO

Possible drawbacks of the solution: using SQL_Latin1_General_Cp850_BIN collation may cause weird sorting in SQL queries, but sorting collation can be easily redefined like this:
select * from Word
order by Word COLLATE SQL_Latin1_General_CP1_CI_AS


Moreover, the sorting it provided by binary collation (SQL_Latin1_General_Cp850_BIN) looks quite reasonable.

You may also use SQL_Latin1_General_Cp850_BIN2 collation for better sorting.


Here’s SQL sample to you to play with:
--drop table t;
select N'3' as Word
into t;

insert into t
select '3' as Word;

select * from t
where Word = N'3';

select * from t
where Word = N'3'

select * from t
where Word = N'3' collate SQL_Latin1_General_Cp850_BIN;

select * from t
where Word = N'3' collate SQL_Latin1_General_Cp850_BIN

Enjoy!

Sunday, April 05, 2009

web.config in IIS 7.0

IIS 7.0 treats Web Application differently from how IIS 6.0 treats Virtual Directory connected to Application pool.
The difference is in how web.config properties are inherited from parent application.
If Virtual Directory in IIS 6.0 is physically located outside of parent web application, then web.config properties are not inherited. Even if logically Virtual Directory is inside parent web application.
So, even if from end user URL looks like this:
http://www.parentwebapp.com/virtualdirectory -- virtualdirectory web app does not inherit web.config properties from parentwebapp.com

IIS 7.0 is smarter than IIS 6.0.
Even if parentwebapp.com and virtualdirectory from above example are mapped to different physical folders like this:
http://www.parentwebapp.com/ -- c:\parentwebapp
http://www.parentwebapp.com/virtualdirectory/ -- c:\virtualdirectory

IIS 7.0 still recognizes that http://www.parentwebapp.com/virtualdirectory/ inherits all web.config settings from http://www.parentwebapp.com/

Such inheritance sometimes causes undesired effects.
For example, if you added HttpModules to parent web app code, but didn't add them to child virtual directory, you may end up with "Could not load type ..." run-time error.

In order to get rid of this error you need from inherited settings.
You can do it like this:

<system.web>
<httpModules>
<remove name="DenyIpAddressModule"/>
</httpModules>
</system.web>
<system.webServer>
<pages theme="">
<modules>
<remove name="DenyIpAddressModule" />
</modules>
</system.webServer>

Note, that in this example I remove "DenyIpAddressModule" twice.
The reason for that is that I added "DenyIpAddressModule" module to parent web.config twice: once as regular httpmodule, and another time as integrated pipeline module.

Wednesday, April 01, 2009

Google Maps API team joke

Google Maps API rolled out unpleasant joke on April 1st day.
Google Maps javascript stopped working today.

There is a quick fix available: switching back to older, more carefully tested version.
(from "v=2.x" to "v=2").

There is a good lesson here: don't use the latest "bleeding edge" version of the code in production environment. Even if it comes from Google.

Technical details are here:
http://groups.google.com/group/Google-Maps-API/browse_thread/thread/193fbebd8066f19f/7fecbfed5908d29e

Tuesday, March 03, 2009

Serialize and Deserialize objects in .NET

I'm not sure why XML standard doesn't allow certain characters to be encoded into XML... and it causes problems.

This C# code:

XmlSerializer xs = new XmlSerializer(typeof(T));
using (MemoryStream memoryStream = new MemoryStream(StringToUTF8ByteArray(objString)))
{
obj = xs.Deserialize(memoryStream);
}

crashes with exception:
System.InvalidOperationException: There is an error in XML document (1, 50). ---> System.Xml.XmlException: ' ', hexadecimal value 0x0C, is an invalid character. Line 1, position 50.

Here's the fix and the fully working version (note that XmlTextReader is used in between MemoryStream and XmlSerializer:


[TestMethod()]
public void SerializeDeserializeObjectTest()
{
SerializeDeserializeObjectTest("test");
SerializeDeserializeObjectTest("\f");
}

private void SerializeDeserializeObjectTest(string input)
{
string serialized = Serializer.SerializeObject(input);
string deserialized = Serializer.DeserializeObject<string>(serialized);
Assert.AreEqual(input, deserialized, input);
}


public static class Serializer
{
public static string SerializeObject(Object obj)
{
MemoryStream memoryStream = new MemoryStream();
XmlSerializer xs = new XmlSerializer(obj.GetType());
XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.UTF8);
xs.Serialize(xmlTextWriter, obj);
memoryStream = (MemoryStream)xmlTextWriter.BaseStream;
return UTF8ByteArrayToString(memoryStream.ToArray());
}

public static T DeserializeObject<T>(string objString)
{
Object obj = null;
XmlSerializer xs = new XmlSerializer(typeof(T));
using (MemoryStream memoryStream = new MemoryStream(StringToUTF8ByteArray(objString)))
{
XmlTextReader xtr = new XmlTextReader(memoryStream);
obj = xs.Deserialize(xtr);
}
return (T)obj;
}

private static string UTF8ByteArrayToString(byte[] characters)
{
UTF8Encoding encoding = new UTF8Encoding();
return encoding.GetString(characters);
}

private static byte[] StringToUTF8ByteArray(string xmlString)
{
UTF8Encoding encoding = new UTF8Encoding();
return encoding.GetBytes(xmlString);
}

}



Thanks to Tom Goff for XML Serialization Sorrows article.

Thanks to Andrew Gunn for XML Serialization in C# article.

Followers

About Me

My photo
Email me: blog@postjobfree.com