I open Database connection in my controller and pass the opened connection to my Model for using that connection.
but since 2nd time calling to the controller(Ajax), it return an error message that say 'Connection must be open.'
I reloaded page, and call the controller again then it works well. but for the 2nd time calling, it keep return that error message.
My controller has the code to open DB Connection, so I believed, it should open database for every processing(Calling). and the (open) code is in using{} block so after using it, it should be closed automatically.
but I think I'm doing wrong :(
here is my code,
public JsonResult myControllerMethod() // Action Controller
{
using (AdsConnection conn = new AdsConnection(connString))
{
conn.Open();
AdsTransaction txn = conn.BeginTransaction(); // Begin Transaction
try
{
MyModel mo = new MyModel();
mo.doProcess(conn); // pass connection to model
txn.Commit();
return Json(new { success = true });
}
catch (Exception e)
{
txn.Rollback();
return Json(new { success = false, message = e.Message });
}
}
}
MyModel
public void doProcess(AdsConncection conn){ // Model
try{
..
//AdsCommand select, update, delete and insert....
..
}catch(Exception e){
throw e;
}
}
Anybody know, what I am doing wrong? please advice me.
Thanks
You shouldn't pass a database connection to your view - your view should accept an object (as a model) that contains "solid" data. A view should have no logic of its own, and a Model's logic should only be concerned with modifying internal state, such as performing validation (not verification) or some internal data transformation. The task of populating a Model from a database should be done by the controller or a separate mapping class (or by some kind of "Populate" method of the model, but this method should be called and contained within the controller's action method).
That said, the problem you're experiencing is because you're using using() blocks. A using() block will always call the IDisposable.Dispose() method of its subject object, in this case a DB connection. SqlConnection.Dispose calls its .Close method, which is why the connection object is closed whenever the method returns.
Related
Im working on a asp.net core website and im trying to make som global validation exception handling using Filters. The backend can at random places throw fluentapi ValidationException and I want to catch these and show the error messages to the user. This filter only cares about ValidationExceptions. All other exceptions will be handled later..
Instead of using a try/catch in every post action in all my controllers, I want to use a filter that catches only ValidationExceptions, add the errors to the ModelState and then return to the original view with the updated ModelState.
I have tried many things but every time I just get a blank page after the filter finishes. I can easily set a new RedirectToRouteResult witht the controller and action from the context. But then I dont have the ModelState and values the user entered..
public class PostExceptionFilter : ExceptionFilterAttribute
{
public override void OnException(ExceptionContext context)
{
if (context.Exception is FluentValidation.ValidationException)
{
var ex = context.Exception as FluentValidation.ValidationException;
context.Exception = null;
context.HttpContext.Response.StatusCode = 200;
context.ExceptionHandled = true;
foreach (var item in ex.Errors.ToList())
{
context.ModelState.AddModelError(item.PropertyName, item.ErrorMessage);
}
// Done with the stuff I want.
// Now please go back to the original view with the updated modelstate and values
}
else if (context.Exception is UnauthorizedAccessException)
{
// Do something else...
}
else
{
// Do something else...
}
base.OnException(context);
}
}
You cannot access the particlar Model(related to Action Method) in Exception Filters. So you have to handle the error at Controller level if you want to add Errors to model.
try
{
//Do something
}
Catch(Exception e)
{
ModelState.AddModelError(string key, string errorMessage);
Return View(model)
}
The error message will present itself in the <%: Html.ValidationSummary() %> in your View
Without try-catch blocks you won't know if exception occured in Action Method, So that you can add Custom Errors to Model.
Do I need to pass a class objects to the Model method and process it one at a time?
Eg.
public async Task<int> SaveCollectionValues(Foo foo)
{
....
//Parameters
MySqlParameter prmID = new MySqlParameter("pID", MySqlDbType.Int32);
prmID.Value = foo.ID;
sqlCommand.Parameters.Add(prmID);
....
}
(OR)
2. Shall I pass the Collection value to the Model method and use foreach to iterate through the collection
public async Task<int> SaveCollectionValues(FooCollection foo)
{
....
//Parameters
foreach(Foo obj in foo)
{
MySqlParameter prmID = new MySqlParameter("pID", MySqlDbType.Int32);
prmID.Value = foo.ID;
sqlCommand.Parameters.Add(prmID);
....
}
....
}
I just need to know which of the above mentioned method would be efficient to use?
Efficient is a bit relative here since you didn't specify which database. Bulk insert might change from one to another DB. SQL Server, for instance, uses BCP, while MySQL has a way to disable some internals while sending many insert/update commands.
Apart from that, if you're submitting a single collection at once and that should be handled as a single transaction, than the best option, from both code organization and SQL optimization, is to use both connection sharing and a single transaction object, as follows:
public void DoSomething(FooCollection collection)
{
using(var db = GetMyDatabase())
{
db.Open();
var transaction = db.BeginTransaction();
foreach(var foo in collection)
{
if (!DoSomething(foo, db, transaction))
{ transaction.Rollback(); break; }
}
}
}
public bool DoSomething(Foo foo, IDbConnection db, IDbTransaction transaction)
{
try
{
// create your command (use a helper?)
// set your command connection to db
// execute your command (don't forget to pass the transaction object)
// return true if it's ok (eg: ExecuteNonQuery > 0)
// return false it it's not ok
}
catch
{
return false;
// this might not work 100% fine for you.
// I'm not logging nor re-throwing the exception, I'm just getting rid of it.
// The idea is to return false because it was not ok.
// You can also return the exception through "out" parameters.
}
}
This way you have a clean code: one method that handles the entire collection and one that handles each value.
Also, although you're submitting each value, you're using a single transaction. Besides of a single commit (better performance), if one fails, the entire collection fails, leaving no garbage behind.
If you don't really need all that transaction stuff, just don't create the transaction and remove it from the second method. Keep a single connection since that will avoid resources overuse and connection overhead.
Also, as a general rule, I like to say: "Never open too many connections at once, specially when you can open a single one. Never forget to close and dispose a connection unless you're using connection poolling and know exactly how that works".
I am developing an asp.net mvc application where user1 could delete data records which were just loaded before by user2. User2 either changes this non-existent data record (Update) or is doing an insert with this data in another table that a foreign-key constraint is violated.
Where do you catch such expected exceptions?
In the Controller of your asp.net mvc application or in the business service?
Just a sidenote: I only catch the SqlException here if its a ForeignKey constraint exception to tell the user that another user has deleted a certain parent record and therefore he can not create the testplan. But this code is not fully implemented yet!
Controller:
public JsonResult CreateTestplan(Testplan testplan)
{
bool success = false;
string error = string.Empty;
try
{
success = testplanService.CreateTestplan(testplan);
}
catch (SqlException ex)
{
error = ex.Message;
}
return Json(new { success = success, error = error }, JsonRequestBehavior.AllowGet);
}
OR
Business service:
public Result CreateTestplan(Testplan testplan)
{
Result result = new Result();
try
{
using (var con = new SqlConnection(_connectionString))
using (var trans = new TransactionScope())
{
con.Open();
_testplanDataProvider.AddTestplan(testplan);
_testplanDataProvider.CreateTeststepsForTestplan(testplan.Id, testplan.TemplateId);
trans.Complete();
result.Success = true;
}
}
catch (SqlException e)
{
result.Error = e.Message;
}
return result;
}
then in the Controller:
public JsonResult CreateTestplan(Testplan testplan)
{
Result result = testplanService.CreateTestplan(testplan);
return Json(new { success = result.success, error = result.error }, JsonRequestBehavior.AllowGet);
}
Foreign key constraint violation should be checked and displayed properly. You can easily check if rows in related table exist and show proper message. The same can be done with row updates. Servers return number of rows affected, so you know what happens.
Even if you don't make these checks, you should catch SQL exceptions. For average application user, message about constraint violation means nothing. This message is for developer and you should log it with ELMAH or Log4Net library. User should see message similar to "We are sorry. This row has been probably modified by another user and your operation has become invalid." and in case he asks developer about it, developer should check logs and see the cause.
EDIT
I believe you should check errors in service. Controller should not be aware of data access layer. For controller, it doesn't matter if you store data in SQL database or in files. Files can throw file access exception, SQL has other ones. Controller shouldn't worry about it. You can catch data access layer exceptions in service and throw exception with type dedicated for service layer. Controller can catch it and display proper message. So the answer is:
public class BusinessService
{
public Result CreateTestplan(Testplan testplan)
{
Result result = new Result();
try
{
using (var con = new SqlConnection(_connectionString))
using (var trans = new TransactionScope())
{
con.Open();
_testplanDataProvider.AddTestplan(testplan);
_testplanDataProvider.CreateTeststepsForTestplan(testplan.Id, testplan.TemplateId);
trans.Complete();
result.Success = true;
}
}
catch (SqlException e)
{
....log in ELMAH or Log4Net using other logging framework...
throw new ServiceException("We are sorry. Your operation conflicted with another operation in database. It has been cancelled.");
}
return result;
}
}
I have a controller action that does some work in the database and then exits when it's finished. This action is being called via jQuery's ajax function with the dataType set to 'json'.
If I set the return type of the action to void, everything will function just fine except Firefox will show an error in the console that says: "no element found".
It makes sense that Firefox would throw this error if it was expecting XML to come back. However, even when I change the dataType property of the ajax call to "text", I still receive the error. In order to get rid of the error with the return type void, I would have to set the Response's ContentType to "text/html". Or I could set the return type to JsonResult and return a new [empty] JsonResult object.
I'm sure there are several ways I can make this error go away, but I wanted to know the proper way to handle actions with no return values being called via ajax.
If it matters, I'm also using the async controller action pattern.
public void DoSomethingAsync(SomeJsonObjectForModelBinding model)
{
// do some database things
}
public void DoSomethingCompleted()
{
// nothing to do...
// what should my return type be?
// do I need to set the content type here?
}
I know this doesn't exactly answer your question, but I would argue that you should always have a return value coming back from an AJAX or web service call. Even if only to tell you that the operation was successful, or otherwise return the error (message) back to you.
I often define a class like this:
public class JsonResultData
{
private bool _success = true;
public bool Success
{
get { return _success; }
set { _success = value; }
}
public object Value { get; set; }
public List<string> Errors { get; set; }
public JsonResultData()
{
this.Errors = new List<string>();
}
}
And then use it to return data or any other call meta data in the JsonResultData wrapper like so:
return new JsonResult {
Data = new JsonResultData { Value = returnValue, Success = true }
};
I can't comment because of my reputation but I still wanted to contribute to clear the confusion in Kon's answer.
In an application I caught all exceptions within an ActionMethod, set an HttpStatusCode and added an error message to the response. I extracted the message in the Ajax error function and showed it to the user.
Everything worked out fine until the application got put on the staging server, who had some kind of settings that did not allow a return message within an erroneous response. Instead some standard Html was transmitted resulting in a JS error processing the response.
In the end I had to rewrite all my exception handling returning my application errors as successful Ajax call (which it actually is) and then differ within the Ajax success function, just the way it should be.
You should not mix system-level and application-level feedback. You may not be able to control the system-level feedback the way your application needs.
I want to be able to check the form inputs prior to launching a long running asynchronous task.
Two approaches that come to mind:
Check values on the Begin method and
throw an exception?
Post to a normal (synchronous method) which validates as per normal. redirects to the asynchonrous method if no errors found.
Throwing an exception i thought would be a simple solution. I can't return the view from the begin method, so the exception is handled on the end method. Only it isn't getting across to the end method (I thought this was the normal pattern)
Validating in a normal synchronous method is fine... but how do i transfer or redirect the request to the asynchronous method???
You don't need to use exceptions or a synchronous method, you can just pass back a different IAsyncResult (assuming that's the pattern you're using - if you're using the event or delegate patterns, you'd still be able to achieve something similar without exceptions).
Here's a simple example of this where we use a dummy delegate to return if there's an error (in this case an invalid ID):
public class MyAsyncController : AsyncController
{
public IAsyncResult BeginFoo(int id, AsyncCallback callback, object state)
{
Action errorDelegate = () => ViewData["errors"] = "Invalid ID";
// Here's our validation check, return the error delegate if necessary
if (id <= 0) return errorDelegate.BeginInvoke(callback, state);
var webRequest = WebRequest.Create("http://www.apple.com");
return webRequest.BeginGetResponse(callback, webRequest);
}
public ActionResult EndFoo(IAsyncResult asyncResult)
{
if (asyncResult.AsyncState is WebRequest)
{
var webRequest = (WebRequest) asyncResult.AsyncState;
var httpResponse = (HttpWebResponse) webRequest.EndGetResponse(asyncResult);
ViewData["status"] = httpResponse.StatusCode;
}
return View();
}
}