1

Our Asp.net web application is using LINQ-to-SQL (Stored Procs are dragged on dropped on dbml file to create classes) and 3 tier architecture is similar to the one below. I have just created rough methods to give reader proper idea so that he can answer well.

namespace MyDataLayer
{
    public class MyDataAccess
    {
        // global instance of datacontext
        MyDataModelDataContext myDB = new MyDataModelDataContext();     (#1)

        public void GetUserIDByUsername(string sUserName, ref int iUserID)
        {
            int? iUserIDout = 0;
            // this will make call to SP in SQL DB
            myDB.USP_RP_GETUSERIDBYUSERNAME(sUserName, "", ref iUserIDout);
            iUserID = (int)iUserIDout;
        }

        public List<USP_APP_USERDETAILSResult> GetUserDetails(string sUserIDs)
        {
            // this will make call to SP in SQL DB
            return myDB.USP_APP_USERDETAILS(sUserIDs).ToList();
        }
        ...
        ... // several CRUD methods
    }
}

namespace MyBusinessLayer
{
    public class SiteUser
    {
        // global DataAccess instance
        MyDataLayer.MyDataAccess myDA = new MyDataAccess();             (#2)
        public void GetUserIDByUsername(string sUserName, ref int iUserID)
        {
            myDA.GetUserIDByUsername(sUserName, ref iUserID);
        }
        public List<USP_APP_USERDETAILSResult> GetUserDetails(string sUserIDs)
        {
            // this will make call to SP in SQL DB
            return myDA.GetUserDetails(sUserIDs);
        }
        ...
        ... // several CRUD methods
    }
}

namespace MyWebApplication
{
    public class BaseWebPage : System.Web.UI.Page
    {
        // static business layer instance
        public static MyBusinessLayer.SiteUser UserBLInstance = new SiteUser();         (#3)                    
        ...             
    }
}
// Index.aspx.cs code fragment
namespace MyWebApplication
{
    public class Index : BaseWebPage
    {       
        public void PopulateUserDropDown()
        {
            // using static business layer instance declared in BaseWebPage
            List<USP_APP_USERDETAILSResult> listUsers = UserBLInstance.GetUserDetails("1,2,3");

            // do databinding and so on ...
        }
        ...             
    }
}

Questions

  • (Ref.#1) Is having global datacontext in DataAccess good approach? yes/no why?
  • If your suggestion is having datacontext per request what is the best practice for that
  • (Ref.#2) Is having global DataAccess instance in BusinessLayer good approach? yes/no why?
  • If your suggestion is having DataAccess instance per request what is the best practice for that
  • (Ref. #3) Is static business layer instance declared in BaseWebPage good approach? yes/no why?
  • Best approach to manage life time of BL instance and DL instance in general

We are facing periodic InvalidCastException on production server for a very simple method which works fine if I restart my application from IIS. When this problem is there we can access the same database from SQL Management Studio and can execute same SP

Our prime suspect about this issue is poor DataContext management and I have read many articles on net about managing life time of DataContext but I am now confused about various approach. That's why I have elaborated my questions so that many in same situation can get clear idea about problem/answer.

Flimzy
  • 60,850
  • 13
  • 104
  • 147
v s
  • 529
  • 7
  • 16

2 Answers2

1

(Ref.#1) Is having global datacontext in DataAccess good approach? yes/no why?

Yes.

However, creating it manually inside the dataaccess class means that you can't control the lifetime of the datacontext. Instead, make it then a constructor parameter so that it is injected into the data access

(Ref.#2) Is having global DataAccess instance in BusinessLayer good approach? yes/no why?

Yes. But refer to 1. - make it injectable via the constructor.

(Ref. #3) Is static business layer instance declared in BaseWebPage good approach? yes/no why?

No. Avoid static for complex objects as usually such objects has non-trivial state. And this is when a lot of nasty issues can happen if you share such objects in a concurrent environment.

To summarize.

public class DataAccess {
   public DataAccess( DataContext context ) { ... }    
}

public class BusinessLayer {
   public BusinessLayer( DataAccess access ) { ... }    
}

public class MyPage : Page {
 ...

 var ctx = TheDataContext.Current;
 var bl = new BusinessLayer( new DataAccess( ctx ) );  
}

with data context shared in a request scope:

public partial class TheDataContext {

  // Allow the datacontext to be shared in a request-scope
  public static TheDataContext Current {
     get {
         if ( HttpContext.Current.Items["context"] == null )
            HttpContext.Current.Items.Add( "context", new TheDataContext() );

         return (TheDataContext)HttpContext.Current.Items["context"];
     } 
  }
}
Wiktor Zychla
  • 44,107
  • 6
  • 65
  • 91
  • (Ref.#3) What if our business layer class has only methods(no members, properties) that just calls methods from dataaccess and does some formating only. In that case can we do it? – v s Aug 22 '12 at 14:44
  • Ok then Where would TheDataContext class be placed in BaseWebPage? why it is partial? – v s Aug 22 '12 at 15:08
  • It's partial because you already have it, created as dbml + cs. – Wiktor Zychla Aug 22 '12 at 16:09
  • I still did not get it. Do I need to create a separate class file with TheDataContext class you specified or I can put it in BaseWebPage. Could you be little descriptive, please? – v s Aug 23 '12 at 06:58
  • My `DataContext` is your `MyDataModelDataContext`. I assume you already HAVE this class. – Wiktor Zychla Aug 23 '12 at 07:11
  • I see there is one empty partial class file in my dbml project. Are you talking about that one? will it be overwritten whenever I do drag and drop of new SP? secondly how will I access this HttpContext there? – v s Aug 23 '12 at 07:15
  • The model class IS overwritten but this is why you create another, separate file and put your partial class definition there (do you really miss the basics on partial classes?). `HttpContext` is available everywhere, just add reference to `System.Web` and `using System.Web`. – Wiktor Zychla Aug 23 '12 at 07:18
  • I do remember the basics but wanted to make sure. I have never accessed the HttpContext in dbml project as it is basically a class file project and was not 100% sure about whether we can add reference of System.Web to that kind of library anyway it is clear now and thanks a ton for your valuable time – v s Aug 23 '12 at 08:25
  • Glad to help. If you found this helpful, consider accepting my answer. Regards. – Wiktor Zychla Aug 23 '12 at 10:22
  • Do I need to have disposing logic in Application_End Request() as per this link http://stackoverflow.com/questions/2482220/attaching-linq-to-sql-datacontext-to-httpcontext-in-business-layer – v s Aug 23 '12 at 14:43
0

In your sample - your MyDataLayer usually has name Repository. Definitely it is good to have DataContext instance in Repositories and do not try to use them outside. So, only in repositories you will have dependency on Linq-To-Sql, which means that you can create Stub objects for these Repositories and really easy test other parts of your application.

Definitely you should Dispose your Data Context instances, DataContext contains too many objects to keep them alive and let GC to kill them. As you can see you don't create any transaction objects when you are working with DataContextes, so I think that LinqToSql based on idea that you should have everything per transaction (of course you can also try to handle transaction manually, but do you really want to do this?). Disposing datacontextes in methods of Repository is a good approach, because this will not allow you to use cool feature of all ORM frameworks: Lazy Load. If you will try to use Lazy Load - you will like it, but usually it is just one of possible performance degradation cause.

Definitely your should use DataContextes for shorter or the same time of Request, don't try to use LongSession (it is when you trying to keep DataContext for more than one Http Request, it is just pain in ass, nothing else, if you want to read about this, just try to read couple articles about Long Running Session in Hibernate, I tried with nHibernate - don't do this at home ;) ).

outcoldman
  • 10,578
  • 2
  • 23
  • 30