views:

387

answers:

4

Say I have a web service that works with a database. Each method opens the database, and then of course closes it on exit.

Is there any method to move the open/close code outside the web method itself? Something like OnBeforeWebMethodCalled / OnAfterWebMethodCalled.

So instead of

[WebMethod]
public void Hello()
{
   OpenDatabase();
   try { } finally { CloseDatabase(); }
}

we will have

private void OnBeforeWebMethodCalled() { OpenDatabase(); }
private void OnAfterWebMethodCalled() { CloseDatabase(); }
[WebMethod]
public void Hello()
{
  // the database is ready here
}

Thanks everybody for suggesting the using keyword but I know about it. The problem is that I have a legacy service of first kind and I'd like to easily wrap the database stuff to make it the second kind.

Now, imagine it's not a database stuff. Imaging I'd like to log web methods entry/exit. Or I want to send emails about which method is called. Whatever. What I really need is to execute some code at entry/exit of the web method. And I don't want to inject this code into every single web method. Ideally if I can catch exceptions, too.

+2  A: 

This is a really really bad idea.

First off, your database access should be wrapped in a using statement. If you aren't going to do that, then the very least you need is a try catch.

Second, how would the web service runtime know whether you really needed to open a DB connection or not anyway?

Finally What if the db call blows up? What would your web method do to handle an orphaned connection? Or, what would the web method do if the open failed?

Chris Lively
See the update to the questions. Also:- web service doesn't need to know; it needs to provide a way to execute my code which does;- if the db call blows up then web method exit will be called and the code there will close the connection;- which is why web method itself doesn't need to care about orphaned connections;- and if the open fails then the web method entry code will throw an exception and the core code won't execute.Now, if there's no way to call web exit after web method throws, you're right - I can't use this technique; but that's the nuance that has to be known.
queen3
The problem is that you can't guarantee the exit would be called in the event of an exception. Unless you are already modifying the web methods to try .. catch everything. Even then, there are exceptions which would still blow past the try catch. The next problem is that the web method itself may not care about an orphaned connection, but the app as a whole (and your database server) will.
Chris Lively
One can guarantee that exit will be called with try/finally. I just want to put this into single method since I hate code duplication. For example, there're techniques like methods decoration in Python and I hoped to find something similar. It can be implemented in simple manner in C# like "public OverridableMethodCall(name, args) { MyOpenDb(); try { DoActualCall(name, args); } finally { MyCloseDb(); } }" - of couse, if framework provides OverridableMethodCall... which is not the case it seems.
queen3
There are several exceptions which will blow past try / finally and try / catch blocks. StackOverflow, certain Security related, ExecutingEngine, etc. A using clause is the only way to ensure the connections are properly cleaned up.
Chris Lively
Not incidentally, you are advocating taking a chance in order to save exactly 0 lines of code per method.
Chris Lively
+1  A: 

Have a private method that gets you an open database connection. Wrap your use of it in a using block, then it will be closed/disposed properly without you having to think about it.

private IDbConnection GetDbConn()
{
    SqlConnection conn = new SqlConnection("connectionstringhere");
    conn.Open();
    return conn;
}

[WebMethod]
public void SomeWebMethod()
{
    using (IDbConnection conn = GetDbConn())
    {
        // your code here
    }
}

Followup

I really don't see how you'll be able to catch exceptions without putting try {} catch {} in each of your web methods.

With regards to running something at the start and end of each web method, perhaps you could look at firing an event, to which methods would be hooked up in the constructor for your web service.

If you need to guarantee that the "end" event would be fired regardless of whether your web method threw an exception, put it in a finally {} block.

This would require you to edit each web method once to add the event code, but then you can add/remove event handlers as required from one central place (the constructor).

[WebService(Namespace = "http://YourWebServiceNamespace")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ToolboxItem(false)]
public class YourWebService : System.Web.Services.WebService
{
  private event EventHandler WebMethodStarted;
  private event EventHandler WebMethodCompleted;

  public YourWebService()
  {
     WebMethodStarted += new EventHandler(YourWebService_WebMethodStarted);
     WebMethodCompleted += new EventHandler(YourWebService_WebMethodCompleted);
  }

  [WebMethod]
  public void SomeWebMethod()
  {
      OnWebServiceStarted();

      try
      {
          // your code here
      }
      catch
      {
          // this is where I suggest you do your exception handling for each webmethod
      }
      finally
      {
          OnWebServiceCompleted();
      }
  } 


  private void OnWebMethodStarted()
  {
      if (WebMethodStarted != null)
          WebMethodStarted(this, EventArgs.Empty);
  }    

  private void OnWebMethodCompleted()
  {
      if (WebMethodCompleted != null)
          WebMethodCompleted(this, EventArgs.Empty);
  }    

  private void YourWebService_WebMethodStarted(object sender, EventArgs e)
  {
      throw new NotImplementedException(); // your code here
  }

  private void YourWebService_WebMethodCompleted(object sender, EventArgs e)
  {
      throw new NotImplementedException(); // your code here
  }
}
tomfanning
OK, thanks for your detailed suggestion. There're other similar solutions, like "using (MethodWrapper w = new MethodWrapper()) { ... }" and then in MethodWrapper ctor/Dispose() I can do things. But the question is about whether ASP.NET provides such functionality already - something like AOP. Sure I can do a lot of things manually... that's not what I really want - bloat methods with the auxiliary code, etc.For example, in global.asax I can probably use HttpApplication.BeginRequest/EndRequest. But this is not service-specific and is not easy to get the request method/parameters.
queen3
Then I think the answer to your original question is simply no.
tomfanning
+1  A: 

I stumbled upon a possible solution to this issue for you

http://www.postsharp.org/

tomfanning
That's exactly what I meant! Well, I didn't really want to go into AOP but since ASP.NET doesn't natively supports this... and this answers "How to handle web method exit" perfectly, which is what this question about, not the database access in a right way... there's no right way in a legacy code ;-)
queen3
A: 

You should use repository class that encapsulates open and close method within itself. In a way it is a bad practise to open and close database connection on front-ends.

public static class DBRepository
{

    public static void SomeOps(string args)
    {
        //open db
        //your ops
        //close db
    }

}

Call DBRepository.SomeOps from web-service.

this. __curious_geek