Sunday, June 28, 2009
On my recent blog post, I demonstrated that I'd been able to submit the same LINQ query to both an in-memory repository and a L2S Repo.

However, after discussing this on StackOverflow, it seems that we must be careful.  While I have seen this technique demonstrated in other articles, I've not found anything from an official perspective, so I will probably err on the side of caution with this one.

While L2O and L2S may overlap on 90% of cases, that 10% is always going to be the one to bite you when you don't have time to react.  So, it's back to a simpler approach.

I'm still going to stick with the Repository pattern, but instead of exposing the Repository as IQueryable<T> (even if the underlying source is IEnumerable<T>) I'm going to encapsulate the actual queries within a Fetch(ICriteria) method instead.  This worked well for me in a previous application, but it has the obvious drawback that we have to define the queries differently for each Repository implementation.

However, it still allows us to abstract our DAL from our Application layer, as shown in this simple diagram:





So we can still use a Domain Driven approach to developing our app, which is great, but we have to ensure that integration testing is thorough when we introduce our other implemented repositories.

Sunday, June 28, 2009 12:21:14 PM (GMT Standard Time, UTC+00:00) | Comments [0] | Database | TDD#
Looking into creating a widget that webmasters can embed on their own page, I have to decide HOW I'm going to develop this.

The options are:

  • IFrame
  • Javascript
There's a really good article here that explains the options.

For this very simple widget, right now I'm thinking IFrame, as there's no point in over-complicating things.  But we'll see when the final requirements spec comes round!

Sunday, June 28, 2009 12:06:47 PM (GMT Standard Time, UTC+00:00) | Comments [0] | Web Design#
Saturday, June 27, 2009
I've started work on a new project recently and the first thing for me to sort out is the Data Access Layer.  Because the Repository pattern served me so well in the past, I'm going to start there.

However, the previous solution used a bespoke QueryBuilder which converted an ICriteria into the appropriate SQL.  This SQL was then just passed through as CommandText on an ADO.NET connection to the appropriate database, Oracle or SQL Server. 

What we did was to mock the Repository using LINQ to Objects, and this allowed us to construct our application in a Domain-Driven fashion.

Great!

However, there was always room for improvement.  I've wanted to use LINQ as my ORM for quite some time now, and I know the purists out there will say that LINQ isn't an ORM, but for practical purposes in this project it's going to be.

Also, I've decided to use L2S rather than the Entity Framework.  My mantra is Design For Test, and right now L2E is just not persistent-ignorant in the slightest.  There are hacks as I've outlined in previous blog posts, but building hacks into the foundation of your application is a recipe for disaster.

While L2S may not be supported in future by MS, who cares?!  It works, plenty of good, solid apps have been built on it, AND IF WE GET THINGS RIGHT, there's no reason why we can't switch to L2E v2.0 next year.

We can do this because we are going to abstract out the actual DataContext, and access our data using POCO and Repository pattern.

In addition, if we can swap out the DataContext, then given that LINQ to Objects and LINQ to SQL queries are the same (or at least I hope they are, more on this later) then we can have a set of queries that we can run on both in-memory and database sources.  Truly Datasource-Agnostic.

I got the inspiration for this from http://compiledexperience.com/Blog/post/Domain-Driven-Design-Repositories-in-LINQ-to-SQL.aspx - and it works!





This diagram shows the LinqToSQL assembly, but we can also replace the SQLDataSource and SQLUnitOfWork with a MemoryDataSource and MemoryUnitOfWork.

For example, if we want to test an in-memory collection, we do the following:

            MemoryUnitOfWork context = new MemoryUnitOfWork();

            Repository<Customer> r = new Repository<Customer>(context);
            r.Save(new Customer(1, "Joe Bloggs"));
            r.Save(new Customer(2, "Joanna Bloggs"));

            IEnumerable<Customer> customers = from c in r.Fetch(null) where c.ID == 1 select c;

            List<Customer> results = customers.ToList<Customer>();

            Assert.AreEqual("Joe Bloggs", results[0].Name);


And if we want to test an actual connection to a database using L2S:

            DataContext db = new DataContext("Data Source=(local);Initial Catalog=DMGTest;Integrated Security=SSPI");

            SqlUnitOfWork context = new SqlUnitOfWork(db);

            Repository<Customer> r = new Repository<Customer>(context);

            IEnumerable<Customer> customers = from c in r.Fetch(null) where c.ID == 1 select c;

            List<Customer> results = customers.ToList<Customer>();

            Assert.AreEqual("Joe Bloggs", results[0].Name);

Note the line

IEnumerable<Customer> customers = from c in r.Fetch(null) where c.ID == 1 select c;

which is identical in both versions.

My next step is to encapsulate the queries using the Specification pattern, as Ritesh shows here.

So now we have completely isolated our domain from our DAL, and with the introduction of the Specification pattern we can look at our queries from a domain perspective also.

The code is just bashed out at the moment, but if you want it then just drop me a line and I'll send it over.



kick it on DotNetKicks.com
Saturday, June 27, 2009 9:59:11 AM (GMT Standard Time, UTC+00:00) | Comments [0] | c# | Database | Patterns | TDD#
Wednesday, June 24, 2009
Some quick notes on some recent research.

Specify pages which should redirect from http to https programatically, which can help out in a test/staging environment:

http://www.codeproject.com/KB/web-security/WebPageSecurity_v2.aspx

http://weblogs.asp.net/pwilson/archive/2004/12/23/331455.aspx


Cross-Domain Scripting, IFrames, SOP (Single Origin Policy) and JSONP

http://remysharp.com/2007/10/08/what-is-jsonp/

http://www.zackgrossbart.com/hackito/jsonp-sop/

http://sazbean.com/2009/02/11/json_and_the_argonauts/

http://softwareas.com/cross-domain-communication-with-iframes

Embedding a script from another domain into your page (example GoogleAnalytics):

<script type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl " : "http://www ");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
</script>
<script type="text/javascript">
var pageTracker = _gat._getTracker("UA-xxxxxx-x");
pageTracker._trackPageview();
</script> 

Wednesday, June 24, 2009 9:09:17 PM (GMT Standard Time, UTC+00:00) | Comments [0] | ASP.NET#
Sunday, June 14, 2009
Over the next month or so, I'll be looking into the Entity Framework again.   I see this as the progression of L2S, and as a Microsoft-backed technology I simply cannot ignore it.  Personally, I would much rather put my faith in this than an Open-Source project such as NHibernate.

However, as we know, it has it's faults.  Never one to shirk from a challenge however, I also have a feeling deep in my bones that there is always a way.  Just check out Jaroslaw Kowalksi's EF POCO Adapter.


And, as I predicted, the hassle from the community meant they simply had to build this in to the next release.  Almost hot off the press, we have POCO in the EF.

Anyway, I'll be keeping a close eye on this.  While I'm an avid ALT.NETter I also realise the pain and hassle that you can cause yourself by going down that route!


Sunday, June 14, 2009 8:33:46 PM (GMT Standard Time, UTC+00:00) | Comments [0] | Entity Framework#
Saturday, June 13, 2009
Not a nice and easy topic for Saturday breakfast, I'll agree.

We've been looking at improving the responsiveness and throughput of our web application.  There is a significant amount of processing and database I/O done on the application-layer, in a COM+ Server.  You can see where this is going, I'm sure.

I won't go in to the technical details, but suffice to say the logical step is to make use of Asynchronous pages in ASP.NET.  This article explains what we needed to do to make this happen, in addition to using custom threads (rather than threads straight out of the thread pool!) so that we maintain a high-level of throughput.  This was in ASP.NET 1.x.

These more recent articles (http://msdn.microsoft.com/en-us/magazine/cc163463.aspx and http://msdn.microsoft.com/en-us/magazine/cc163725.aspx) quickly outlines the new technique.

It's important to remember that this is only a step in the right direction, we need to make sure that the back-end engine itself is all tickety-boo.


Saturday, June 13, 2009 9:40:04 AM (GMT Standard Time, UTC+00:00) | Comments [0] | ASP.NET#
Friday, June 12, 2009
I've been recently putting the search engine project through it's paces.  I know that searching for Type A entities return in ~50ms (nice) but Type B entities return in ~1-2 seconds (ouch).  Having said that, I know why - the database query for Type B is horrendous at the moment.  The schema is changing drastically anyway so no point in putting that effort in now.

So I ran it via WAST and got some pretty decent results back.  While it does the job, there are obviously better tools out there.  And some of these can be expensive.

I've had a go of WAPT and been really impressed.  The trial version only allows 20 concurrent users, but you can do all sorts of things such as ramp up over time, specify random delays between 'clicks' and so on.  While my application is primarily AJAX, these are just treated as your run-of-the-mill HTTP requests.

At the end of it all I get a neat report, including interactive charts, which let me see when it reaches the maximum amount of throughput before it starts to decline.

With just Type A entities, it just keeps those pages coming.  With Type B entities...well, we know we have to improve!

Friday, June 12, 2009 9:30:04 AM (GMT Standard Time, UTC+00:00) | Comments [0] | ASP.NET#
Search
Archive
Links
Categories
Admin Login
Sign In
Blogroll