December 2006 - Posts

Data Access usind DLinq

DLinq is so much fun. It's so amazingly simple to write data access layer that generates really optimized SQL. If you have not used DLinq before, brace for impact!

When you use DLinq, you just design the database and then use SqlMetal.exe (comes with Linq May CTP) in order to generate a Data Access class which contains all the data access codes and entity classes. Think about the dark age when you had to hand code all entity classes following the database design and hand code data access classes. Whenever your database design changed, you had to modify the entity classes and modify the insert, update, delete, get methods in data access layer. Of course you could use third party ORM tools or use some kind of code generators which generates entity classes from database schema and generates data access layer codes. But do no more, DLinq does it all for you!

The best thing about DLinq is it can generate something called Projection which contains only the necessary fields and not the whole object. There's no ORM tool or Object Oriented Database library which can do this now because it really needs a custom compiler in order to support this. The benefit of projection is pure performance. You do not SELECT fields which you don't need, nor do you contruct a jumbo object which has all the fields. DLinq only selects the required fields and creates objects which contains only the selected fields.

Let's see how easy it is to create a new object in database called "Page":

var db = new DashboardData(ConnectionString); var newPage = new Page(); newPage.UserId = UserId; newPage.Title = Title; newPage.CreatedDate = DateTime.Now; newPage.LastUpdate = DateTime.Now; db.Pages.Add(newPage); db.SubmitChanges(); NewPageId = newPage.ID;

Here, DashboardData is the class which SqlMetal.exe generated.

Say, you want to change a Page's name:

var page = db.Pages.Single( p => p.ID == PageId ); page.Title = PageName; db.SubmitChanges();

Here only one row is selected.

You can also select a single value:

var UserGuid = (from u in db.AspnetUsers where u.LoweredUserName == UserName && u.ApplicationId == DatabaseHelper.ApplicationGuid select u.UserId).Single();

And here's the Projection I was talking about:

var users = from u in db.AspnetUsers select { UserId = u.UserId, UserName = u.LoweredUserName }; foreach( var user in users ) { Debug.WriteLine( user.UserName ); }

If you want to do some paging like select 20 rows from 100th rows:

var users = (from u in db.AspnetUsers select { UserId = u.UserId, UserName = u.LoweredUserName }).Skip(100).Take(20); foreach( var user in users ) { Debug.WriteLine( user.UserName ); }

If you are looking for transaction, see how simple it is:

using( TransactionScope ts = new TransactionScope() ) { List<Page> pages = db.Pages.Where( p => p.UserId == oldGuid ).ToList(); foreach( Page page in pages ) page.UserId = newGuid; // Change setting ownership UserSetting setting = db.UserSettings.Single( u => u.UserId == oldGuid ); db.UserSettings.Remove(setting); setting.UserId = newGuid; db.UserSettings.Add(setting); db.SubmitChanges(); ts.Complete(); }

Unbelievable? Believe it.

You may have some mixed feelings about DLinq performance. Believe me, it generates exactly the right SQL that I wanted it to do. Use SqlProfiler and see the queries it sends to the database. You might also think all these "var" stuffs sounds like late binding in old COM era. It will not be as fast as strongly typed code or your own hand written super optimal code which does exactly what you want. You will be surprised to know that all these DLinq code actually gets transformed into pure and simple .NET 2.0 IL by the Linq compiler. There's no magic stuff or no additional libraries in order to run these codes in your existing .NET 2.0 project. Unlike many ORM tools, DLinq also does not heavily depend on Reflection.

Posted by omar with 1 comment(s)
Filed under:

Executing one workflow from another synchronously

The InvokeWorkflow activity which comes with Workflow Foundation (.NET 3.0) executes a workflow asynchronously. So, if you are calling a workflow from ASP.NET which in turn calls another workflow, the second workflow is going to be terminated prematurely instead of executing completely. The reason is, ManualWorkflowSchedulerService will execute the first workflow synchronously and then finish the workflow execution and close down. If you used InvokeWorkflow activity in order to run another workflow from the first workflow, it will start on another thread and it will not get enough time to execute completely before the parent workflow ends.

Here you see only one activity in the second workflow gets the chance to execute. The remaining two activities do not get called at all.

Luckily I found an implementation of synchronous workflow execution at:

http://www.masteringbiztalk.com/blogs/jon/PermaLink,guid,7be9fb53-0ddf-4633-b358-01c3e9999088.aspx

It's an activity which takes the workflow as input and executes it synchronously. The implementation is very interesting to see. Please see the original blog post for details.

Posted by omar with 114 comment(s)
Filed under:

XLinq: Reading RSS and Atom using XLinq

I am playing around with XLinq. I made a RSS Viewer which downloads RSS/Atom feed and shows a list of links of titles.

XLinq is so unbelievably easy to use. See in less than 10 lines I can populate a DataList full of links from RSS/Atom feed. First I made a DataList:


< asp:DataList ID ="FeedList" runat ="Server" EnableViewState ="False" > < ItemTemplate > < asp:HyperLink ID ="FeedLink" runat ="server" Target ="_blank" CssClass ="feed_item_link" NavigateUrl ='<%# Eval("link") % > '> < %# Eval ("title") % > </ asp:HyperLink > </ ItemTemplate > </ asp:DataList >

Now use XElement.Load to load a feed from any Url.


feed = XElement.Load(url);

After this, we do a select on the <item> nodes and create a projection of each node which contains only the title and link node values. The project acts as a Data Bound Item to the DataList.


if ( feed.Element( " channel " ) != null ) FeedList.DataSource = (from item in feed.Element( " channel " ).Elements( " item " ) select new { title = item.Element( " title " ).Value, link = item.Element( " link " ).Value }).Take( 3 );

For Atom, it's a bit difficult to discover. You need to use Xml Namespace in order to read through the Atom feed:

XNamespace ns = "http://www.w3.org/2005/Atom";


else if ( feed.Element(ns + " entry " ) != null ) FeedList.DataSource = (from item in feed.Elements(ns + " entry " ) select new { title = item.Element(ns + " title " ).Value, link = item.Element(ns + " link " ).Attribute( " href " ).Value }).Take( 3 );

Cool thing is that you can do paging easily by adding the Take and Skip methods at the end of Linq expression as I have done here. Here you see only Take which takes only the specified items from the feed. If you use Skip, then it will skip elements from beginning.

Posted by omar with 2 comment(s)
Filed under:

Database connection string wrong in MSDN Subscription website

This is one of those moments in history which you must be really lucky to witness. Can you believe MSDN actually had a connection string problem in their website which were exposed wide open to the public? Also they deployed the site in debug mode in order to see the error. Moreover, they actually turned on showing remote errors. Must have been really hard to find what was wrong with the site.

So, what we learn from here?

  • Don't deploy production site in debug mode
  • Do not set "off" to <customErrors>. Anyone can see stack trace of your web application. Hackers can collect valuable information from these stack traces
  • Put enough logging in your code so that you can analyze server side log in order to find out what's wrong with your web app. Don't just turn off custom errors in order to see why the site is not working.
  • Put a good custom error page which apologizes to users and gives them enough links to either contact support or go to some other pages.
  • Produce error alerts via email, SMS or IM Client when your site experiences such problems. This is the best way to learn about fatal errors on site and take action quickly.
Posted by omar with 4 comment(s)
Filed under:

Automate website deployment using Powershell

I published an article which automates website deployment.

http://www.codeproject.com/dotnet/DeploySite.asp

The Powershell script does the following for you:

· Maintains different configuration information for different deployments. For example, different connection strings for development servers and production servers (one or more production servers).

· Creates a deployment folder using the deployment date, time, and version so that you have a separate folder for each deployment and can keep track of things deployed on a day, e.g., 20061214-1.

· Copies only the change files and some predefined files to the deployment folder. So, you don't deploy the whole website every day.

· Copies the web.config and customizes the <appSettings>, <connectionString>, <assemblies> etc., as per the deployment configuration. For example, you can have different connection strings for different servers.

· Updates all JavaScript files with a version number so that in every deployment, a new file gets downloaded by client browsers.

· Updates default.aspx automatically with the modified script file name.

· Compresses all JavaScript files that gets deployed.

· Compresses all static HTML files using an Absolute HTML Optimizer.

· Creates a zip file which contains the deployment package.

· FTP the zip file to a target server.

So all you need to do is, run the script, extract the zip on server and voila!

If you like it, please vote for me.

Posted by omar with 4 comment(s)
Filed under:

Reduce web site build time

When you have a pretty large web site in Visual Studio 2005, the site build time grows dramatically and it becomes very difficult to change code and then hit F5 (or Ctrl+Shift+B) in order to see if the project builds properly or not. In Pageflakes, we have a giant web site. It takes so long to build the site that we generally issue the build command, go to kitchen and make a cup of tea, drink it, come back and see the site still building. Generally when we do this 20 to 30 times per day, we start feeling sick (not because of VS 2005 instead of too much tea).

Here's a cool idea we tried. You can make folders hidden by going to Windows Explorer, go to Folder properties, check mark "Hidden" and click OK and then select "Apply to current item only". This will make the folder hidden and the folder will disappear from Windows Explorer unless you have turned on the option to show hidden files and folders. You will also see the folders disappeared from Visual Studio. Now we use Total Commander instead of Windows Explorer so hidden folders are not a problem to us. Bascially none of us remember anymore how to use Windows Explorer because we are so used to Total Commander now. Try it, it will change your life.

When you make folders hidden, Visual Studio will not build them! So you can make App_Data, App_Themes, images, stylesheets, javascripts, html files hidden and Visual Studio will skip them. Around 70% of our web site is non C# code. So, we gained dramatical reduction in web site build time by trying this idea. Another idea is to move all classes from App_Code to external DLL project. Thus they will build once and VS will not build them again and again if you make some changes in some codebehind file or some .aspx or .ascx file. This will also give you significant build time reduction.

Of course you can turn off Build Website and use Build Page option. But that does not help. We want to ensure the web site code is not broken due to any change. So, we need Build Website option.

Posted by omar with 11 comment(s)
Filed under:

ASP.net Ajax under the hood secrets

I have published a new article in codeproject:

ASP.net Ajax under the hood secrets

You will find the following tricks on it:

  • Batch call advantages and disadvantages
  • Implement auto retry in all web method call by modifying Ajax core framework
  • Implement queue based web method call in order to prevent browser from getting stuck with too many Ajax calls
  • Caching web method response, fix bug in ASP.net 2.0 cache header problem
  • How slow is Http Post, capture data transfer over the wire and see

Some of the techniques may be known to you if you have read my earlier posts. But I have converted all code to the latest ASP.net Ajax Beta 2 version which is not available in the blog posts.

Please rate the article if you like it at codeproject.

Also please digg this article.

Posted by omar with 10 comment(s)
Filed under: