0

I have a web app, this app as you already know will have a lot of requests, and each request will run on a different thread, meaning that if I use singleton to access my DAL library it will not be a problem.

However I'm unsure about wether this is the best approach, because I read that one request my use different threads sometimes, and I have also read that locking threads may cause a performance lost sometimes when using single instances.

Just so you understand me better this is what I plan to do:

DAL <- SingleInstance <- BAL <- SingleInstance <- Controllers <- Views

Is this a good approach?

This is the singleton I plan to use:

     public static Products Instance
        {
            get
            {
                return Nested.instance;
            }
        }

        class Nested
        {
            // Explicit static constructor to tell C# compiler
            // not to mark type as beforefieldinit
            static Nested()
            {
            }

       internal static readonly Products instance = new Products();

Note: My Dal will access the database using ADO.NET(I have my reasons to use ado), and the BAL will only use this method to do select or CRUD operations.

My Ado.NET code:

public static readonly string ConnectionString = @"Server=localhost;Database=test;Uid=root;Pwd=test;";

    public bool IsProduct(string name)
    {
        var conn = new SqlConnection(ConnectionString);
        bool result;
        try 
        {
            conn.Open();
            var command = new SqlCommand();
            SqlParameter[] parameters = new SqlParameter[1];
            parameters[0] = new SqlParameter("@Product", name);
            command.Connection = conn;
            command.CommandText = "SPC_GET_PRODUCT";
            command.CommandType = System.Data.CommandType.StoredProcedure;
            result = Convert.ToBoolean(command.ExecuteScalar());
        }
        finally 
        {
            conn.Close();
            conn.Dispose();
        }
        return result;
    }

Thanks.

user3044096
  • 171
  • 1
  • 17
  • We have no idea. We can't see how your DAL is implemented. Is it Entity Framework? Is it in its own service? What does your singleton do to "access" the DAL? – Erik Funkenbusch Mar 30 '15 at 14:52
  • That doesn't help much, nor does it answer any of the questions I asked. – Erik Funkenbusch Mar 30 '15 at 15:06
  • Is it Entity Framework? No, it's ADO.NET.What does your singleton do to "access" the DAL? Products.Instance.GetProducts(); – user3044096 Mar 30 '15 at 15:08
  • And what does "GetProducts()" do? it's that code that we have to see whether it is thread safe or not. – Erik Funkenbusch Mar 30 '15 at 15:10
  • It does al the sqllcommand, sqlconnection, executeReader..etc and ado.net stuff – user3044096 Mar 30 '15 at 15:14
  • Yes, and HOW you do that code is important, and tells us whether it is thread safe.. refusing to show any of it means we can't help you. – Erik Funkenbusch Mar 30 '15 at 15:19
  • Ok, the code you posted is thread safe, since each call to the method will create new instances of the local objects. However, you need to be careful that all your code works this way and you're not using any member variables that can cause race conditions. In fact, you can just as easily mark this method as static, which will prevent someone from adding a member variable accidentally. – Erik Funkenbusch Mar 30 '15 at 15:26
  • And for that matter, if all your methods are static (or able to be static), then what reason do you need for a singleton in the first place? You don't need an instance of the class at all. – Erik Funkenbusch Mar 30 '15 at 15:32

1 Answers1

3

In general, it's probably not a good idea, for a couple reasons:

  • Singleton's are really hard to use with multiple threads for anything complex. It's unlikely most of the libraries you'll be calling into (like Entity Framework) are thread-safe, so you'll need to do a ton of locking to protect resources.

  • You'll almost certainly suffer performance-wise waiting for locks, as opposed to just creating new instances of your service layer. There's no point to having a fully asynchronous platform if everyone is waiting for a single database context.

  • They are difficult to unit test

  • It is semantically incorrect. Singleton's mean's there's just one instance of the class. It doesn't make sense that you'd only have one instance of your business logic running at some time.

Singleton's have their place for simple things, like accessing configuration data, or when creating an instance is really expensive. But in almost all other cases, there's a better way to do it.

There are other answers that explain all the problems with Singleton's.

Community
  • 1
  • 1
mfanto
  • 14,168
  • 6
  • 51
  • 61
  • My DAL will be with ADO.net – user3044096 Mar 30 '15 at 15:00
  • ADO.net is not thread-safe. You'll need to lock access while a single request gets to use the database. http://stackoverflow.com/questions/7316304/is-sqlconnection-sqlcommand-thread-safe – mfanto Mar 30 '15 at 15:01
  • I know, but look at the code I posted, it doesn't use locks and it is thread safe. – user3044096 Mar 30 '15 at 15:06
  • That's only the code to create a singleton. You still need to add in your code, which is when it stops being thread-safe. The moment you have 2 requests do Products.Instance.Database or whatever, you're going to hit errors. – mfanto Mar 30 '15 at 15:08
  • I don't understand why you say it'll hit errors, if it's thread safe. – user3044096 Mar 30 '15 at 15:11
  • I understand what you say now, but my code is only going to do sqlcommand, sql reader stuff, I don't see why it would hit any error. – user3044096 Mar 30 '15 at 15:15
  • It's not thread safe. All you have to do is look at MSDN: https://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlconnection%28v=vs.110%29.aspx You posted a static constructor. That doesn't have anything to do with whether or not ADO.net is thread safe. – mfanto Mar 30 '15 at 15:15
  • If I understand correctly, even if ADO.NET is not Thread Safe, my Ado.net code will be running on the same thread than the instance does, so I don't see why that is a problem. – user3044096 Mar 30 '15 at 15:20
  • That's not what that means. Let's say you have 2 requests to your site. The first request will run on Thread 1, and the second request will run on Thread 2. If both threads call Products.Instance.GetProducts(), then both threads will be using the same SqlConnection, which is not going to work. – mfanto Mar 30 '15 at 15:23
  • How will they be using the same sql connection if I create a new connection on each method? and each thread has its on separate method? and everytime I create a new connection the connection pool creates a new connection?, See the code I just posted, because I'm confused now. – user3044096 Mar 30 '15 at 15:25
  • The code you posted is fine, but you're going to have a lot of duplicated logic this way. – mfanto Mar 30 '15 at 15:29
  • No it's not. Creating a new SqlConnection for every method is not going to improve performance. http://stackoverflow.com/questions/1404261/how-bad-is-opening-and-closing-a-sql-connection-for-several-times-what-is-the-e – mfanto Mar 30 '15 at 15:32
  • What I mean is that performance is better than using Entity Framework – user3044096 Mar 30 '15 at 15:33
  • @mfanto - the url you linked to explicitly talks about connection pooling and how creating a new SqlConnection is not costly. – Erik Funkenbusch Mar 30 '15 at 15:34
  • It might use connection pooling, but creating a bunch of new SqlConnection's to service a single request is still going to be worse than using a single instance, for what I'm going to imagine is no real benefit – mfanto Mar 30 '15 at 15:37
  • @mfanto - not if you have to lock the code to prevent multi-threaded access. Six of one, half a dozen of the other. – Erik Funkenbusch Mar 30 '15 at 15:39
  • Of course, but that's why I think this pattern is bad overall – mfanto Mar 30 '15 at 15:42