I'm experiencing a "strange" situation with a live ASP.NET MVC 3 app. The error start on production after X hours of use. I did not have been able to reproduce the error on my development machine.
Here is my controller action signature:
[HttpPost]
public ActionResult AddBanking(int id, int? page, int bankId,
string q, int? searchFlag, string query, string accountNo,
string accountManager, bool? personnal, int? branchId,
int? selectedId, BankSearchModel data)
The basic idea is that the controller is use for two forms on the View, one for searching where searchFlag is a Hidden field and another form for adding, here is a basic code structure.
try
{
if (searchFlag.HasValue)
{
var vm = svc.FetchBanks(bankId, q);
return View(vm);
}
else
{
bool valid = true, isIndividu = false;
// some code
if(!valid) // <- this is where the line 106 is
{
}
}
}
catch(Exception ex)
{
ex.Data.Add("context", "AddBanking - THIS IS IT");
Log.Error(ex);
return RedirectToAction("Error", new { id = 0 });
}
The error occurs after long periods of time the app run flawlessly, all of a sudden, that exception is caught, but when the users submit the first form (for searching -> searchFlag = 1), so in my example it entered the first if statement.
This is the error and stack trace
context: AddBanking - THIS IS IT
Message: Object reference not set to an instance of an object.
Stack:
at XYZ.Controllers.BanksController.AddBanking(Int32 id, Nullable`1 page, Int32
bankId, String q, Nullable`1 searchFlag, String query, String accountNo, String
accountManager, Nullable`1 personnal, Nullable`1 branchId, Nullable`1 selectedId,
BankSearchModel data) in E:\Projects\XYZ\ABC\123.Web\Controllers\BanksController.cs:line
106
How can it be possible to throw exception on a if statement with a non-nullable bool ?
Since there is a return View() in my first if block, and I'm 100 % certain it entered there how come the exception is on the line 106 where the execution should not even go there.
This is something that happen only after long period of production time, yesterday (8 to 5) this process worked, and this morning bang the exception is throwing, but only in production (Windows 2008, ASP.NET MVC 3). From my developement machine with the same database and same data posting to the page is working.
My main question, how am I suppose to debug this, at first I thought that the stack trace does not returned the right line number, so I added a try/catch inside the action, yet it still return the if(!valid) as NRE...
I would appreciate any idea / guide line. Of course I could separate the two process inside the action and it might fix the problem, but I would rather like to understand what I'm doing wrong in the example.
Edit: I'm completely clueless
By the time I asked this question, the page worked without any change in code and for the exact same data posted.
Edit 2 # 10:30 2011/06/01
Thanks for your suggestions, but I'm really thinking this is really something harder to find. The bug did re-appear today but the app was working from 1 hour after I post this question yesturday until today # 10 am.
Here is more detail on what I've done so far to try to understand what's going on:
I've rebuilt the app (no code changes, and re-deploy bin, views) with .pdb files.
I've put try/catch on every path that the execution should take here is the exact scenario:
View:
#using (Html.BeginForm())
{
#Html.ValidationSummary()
<fieldset>
#Html.Hidden("searchFlag", 1)
#Html.Textbox("q")
<input type="submit" value="Chercher" /></td>
</fieldset>
}
svc cannot be null because I have it set on the controller like this:
[Authorize]
public class BanksController : BaseController
{
BankService svc = new BankService();
...
}
The FetchBanks method
public BankSearchModel FetchBanks(int bankId, string query)
{
return Execute<BankSearchModel>(db =>
{
try
{
// some linq stuff
}
catch(Exception ex)
{
XYZ.Log.Error(ex); // <= note1
}, "Error returned by Execute");
}
My Execute method
protected static T Execute<T>(Func<XYZDbContext, T> query, string errorMessage, bool deferredLoading)
{
try
{
using (XYZDbContext db = new XYZ...())
{
#if DEBUG
db.Log = new DebuggerWriter();
db.CommandTimeout = 3 * 60;
#endif
if (!deferredLoading)
db.DeferredLoadingEnabled = false;
return query(db);
}
}
catch (Exception ex)
{
#if DEBUG
Debug.WriteLine(ex.Message + "\r\n" + ex.StackTrace.ToString());
throw;
#else
ex.Data.Add("context", "Manager, executing query");
XYZ.Log.Error(ex);
return default(T);
#endif
}
}
So again, I understand that the line 106 is not the real error here, but I have try/cath in every single method that the execution should go when the searchFlag is set to 1 (from the first form of the view. Still the only Log.Error(ex) I got was the one telling me there is an error on my contorller at line 106.
Note1 If the error would have come from the FetchBanks method it would have entered the catch inside that method and send me and email with stack trace of that method.
At the end of my FetchBanks I return a BankSearchModel which as all List so all databases query are executed before returning to the controller.
And again, how can it work for the same data posted all day long and suddently stop working. Would that be possible that the signature of the controller with all my null object would cause that behaviour?
This is the only email I got after adding try/catch everywhere that should have send me an error. i.e no other method are entering their catch (The execute, the FetchBanks) only the controller action. I would really like to understand what's going on.
New error occured at 6/1/2011 9:48:13 AM
context: AddBanking - THIS IS IT
Message: Object reference not set to an instance of an object.
Stack:
at XYZ.Web.Controllers.BanksController.AddBanking(Int32 id, Nullable`1 page, Int32
bankId, String q, Nullable1 searchFlag, String query, String accountNo, String
accountManager, Nullable1 personnal, Nullable1 branchId, Nullable1 selectedId,
BankSearchModel data) in
E:\Projects\HiddenForObiousReason\Controllers\BanksController.cs:line 106
After separating my action into two disctinct action (for the two forms in the view) I discover that the errors was relating to the second form and related to the validation of the Model passed.
Here are my two actions now:
[HttpPost]
public ActionResult AddBanking(int id, int? page, int bankId, string q)
[HttpPost]
public ActionResult CreateBanking(int id, int? page, int bankId, string query, string
accountNo, string accountManager, bool? personnal,
int? branchId, int? selectedId, BankSearchModel data)
The error was thrown when the first form was posted, but the Html.ValidationSummary was not writing any errors to the view. After separating the action no error were thrown on the first form, but only on the second and now the ValidationSummary is writing to the View. That is normal and I understand that the first form now do not validate the Model.
What I still cannot fully understand exactly why the error was raising on batch of 15 minutes once a day (from 8am to 5pm). If someone has explanation I would appreciate it. Why a form post with the exact same data works and later do not work (the two posts were supposed to fail since the Model Validation was the cause of the error).
That was probably my mistake to have 1 action for two distinct functionality.
To debug this, check the objects for null.
I wouldn't worry about line 106 so much, check the object(s) in the code for null.
Example:
if (svc == null)
{
Log.Error(new Exception("svc is null!");
}
You have lots of strings in that method call, strings default to null if they are unassigned, so that could be a source of the error as well.
Related
I have two methods in my controller that are called via ajax on click. Both do the exact same thing (retrieving the same data from a database) and return a partial view along with the model that contains the retrieved data. The only difference is the view.
public PartialViewResult FormA()
{
[...// Code]
return PartialView("_FormA", ModelWithData)
}
public PartialViewResult FormB()
{
[...// same Code as in FormA()]
return PartialView("_FormB", ModelWithData)
}
Both views use the same data but show different things.
If FormB() is called FormA() definitely has been called before.
There must be a way to bypass the second method/database request. It perceptibly slows down the application due to the additional database request.
My question seems really stupid to me, but I'm not able to find a workaround...
Thx for your help!
Yes sure by passing some kind of filter to your action method like below
public PartialViewResult ShowForm(string filter)
{
if(TempData["model"] == null)
{
[...// Code]
TempData["model"] = ModelWithData;
}
if(filter == "some_condition")
return PartialView("_FormA", TempData["model"] as ModelWithData);
else
return PartialView("_FormB", TempData["model"] as ModelWithData);
}
Got your point now. You can use any type of state management mechanish. Say TempData
I'm not really sure what is the prefered way when dealing with record not found in the database. Is it better to write Find method which returns null or Get method which returns RecordNotFoundException?
[AuthenticateFilter(UsernameAndSecretKey)]
[Route("api/v1/activities/emails/{id}")]
[HttpGet]
public IHttpActionResult GetEmailActivity(int id)
{
try
{
// business logic service, could use only db service but this way we can do unit tests (just fill bl service method with fake objects)
var service = new EmailActivityBlService();
// 1. use Find method which returns null in case record with provided id does not exist in db
var model = service.FindActivity(id);
if( model != null )
return Ok(model);
return NotFound();
// 2. or is this approach better
// throws RecordNotFoundException in case row by id is not found in database
return Ok(service.GetActivity(id));
}
catch(RecordNotFoundException e) { return NotFound(); }
catch(Exception e) { return InternalServerError(e); }
}
EmailActivityBlService has next code in case anyone interested (showing only the important part):
private EmailActivityDbService _dbService;
public EmailActivityModel GetActivity(int id)
{
var model = this._dbService.GetActivity(id);
if( model == null )
throw new RecordNotFoundException(); // I suppose System.Data.ObjectNotFound is also suitable
return model;
}
public EmailActivityModel FindActivity(int id)
{
// typical entity framework query
// using(var context = new ..) { return contect.EmailActivity.Where()..SingleOrDefault().ConvertToModel();
return this._dbService.GetActivity(id);
}
UPDATE
Talked with my colleagues, we decided to go with this solution. As why GetActivity returns null instead of throwing Exception, I prefer answer from rboe:
So return null if it is can happen in your domain, that records do not exist (in my experience this is most often the case). If you expect a record to exist and it is not there, then it is valid to throw an exception.
[AuthenticateFilter(UsernameAndSecretKey)]
[Route("api/v1/activities/emails/{id}")]
[HttpGet]
public IHttpActionResult GetEmailActivity(int id)
{
var service = new EmailActivityBlService();
var model = service.GetActivity(id); // returns null in case activity is not found
if( model != null )
return Ok(model);
return NotFound();
}
We avoided any try-catch in the methods and put global filter when Exception occurs:
File: App_Start\WebApiConfig.cs
public class WebApiExceptionFilter : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext actionExecutedContext)
{
actionExecutedContext.Response = actionExecutedContext.Request.CreateErrorResponse(HttpStatusCode.InternalServerError, actionExecutedContext.Exception.Message, actionExecutedContext.Exception);
}
}
Both ways are valid ones.
It is a different emphasis whether you use exceptions or the return value null to indicate non existing records.
Exceptions exist to signal an error state (something happened that is abnormal). The code in the catch-handler is focused on how to deal with an error and not to contain business logic.
If you return null then it will be a normal and 'non exceptional' state in your model.
So return null if it is can happen in your domain, that records do not exist (in my experience this is most often the case). If you expect a record to exist and it is not there, then it is valid to throw an exception.
I disagree with the other answer. In the case of a GetyById method, I wouldn't say to return null instead of throwing because you could argue it was "expected" that there might not be a record with the requested id. This "exceptions for exceptional situations," while often stated, I don't really think is the best way to think about the method's contracts. APIs should make semantic sense, ideally.
Instead, I suggest to throw exceptions whenever the method cannot do what it was told to do. So GetById methods should thrown an exception in the event there is no such record with the requested id in the system. The Find method should probably return an enumerable, which of course could be empty in the event no records match the criteria given.
An API which has a FindById method strikes me as odd; if you are giving the API an ID, that implies the caller could somehow have learned the ID in a previous API call, and so the API shouldn't need to "find" an already known to exist record. It should provide a way to get the record directly by its id. Instead Find should be for locating records when you aren't sure they exist, and using some other criteria.
Given the web service call, I would go with the service calling the GetById method, as the web service caller also learned the id somehow. If the id turns out not to exist, the library can throw the RecordNotFoundException, which causes the service call to return 404.
The following two links access the same action method:
http://stage.bullydog.com/Products/accessories/podmount and http://stage.sctflash.com/Products/accessories/podmount
I use Request.Url.Host to determine the brand of products I want to return from a database. When I access http://stage.bullydog.com/Products/accessories/podmount first, Request.Url.Host contains the value stage.bullydog.com, but if I then go to http://stage.sctflash.com/Products/accessories/podmount, Request.Url.Host may contain stage.sctflash.com or it may contain stage.bullydog.com.
The action method that is called is:
public ActionResult GetAccessoriesByType(RenderModel model, string id)
{
Common _common = new Common();
string brand = Request.Url != null ? _common.GetProductBrand() : BrandType.SCT;
var productSearchResultsModel = new ProductSearchResultsModel
{
Accessories = _accessoryRepository.GetAccessoriesByType(id, brand)
};
return View("~/Views/accessories.cshtml", productSearchResultsModel);
}
The code that gets the brand is:
public class Common
{
public string GetProductBrand()
{
var host = HttpContext.Current.Request.Url.Host;
if (host.Contains("sctflash"))
return BrandType.SCT;
if (host.Contains("bigrig") || host.Contains("bigrigs"))
return BrandType.BigRig;
if (host.Contains("bullydog"))
return BrandType.BullyDog;
return BrandType.SCT;
}
}
How can I ensure the Request.Url.Host contains the proper host when the same action method is accessed from two different hosts?
You can see this in action if you go to http://stage.bullydog.com/Products/accessories/podmount and then go to http://stage.sctflash.com/Products/accessories/podmount and refresh either one, the logo should change which means that the value returned by Request.Url.Host was incorrect.
Also, can GetProductBrand be static and still be thread-safe in this case?
The reason why accessing another website was bringing back the one websites content and the Request.Url.Host had the other websites information was because I had declared OutPutCache[Duration=60] at the top of my controller. If I waited 60 seconds and then refreshed, the correct data for each website would return. Once I removed this from the controller, everything worked as expected.
I have a method inside MVC Controller which is called from href inside anchor tag.
public ActionResult DoSomething(string value)
{
if(true)
{
return new RedirectResult("http://google.com");
}
}
when I debug and hit that method Response.Redirect does nothing no exceptions either. any ideas?
Thanks in advance!
Use Redirect
return Redirect("http://www.google.com");
Response.Redirect is not preferred way of doing redirects in asp.net mvc
Response.Redirect and ASP.NET MVC – Do Not Mix
Update: It seems that you are trying to redirect ajax request. If you redirect ajax request, your main page won't be redirected.
There are a few things you need to do here to avoid all these issues.
Starting with the AJAX errors you're getting, they most like relate to the javascript debugger, which Microsoft refer to as "BrowserLink".
If you use Firefox or Chrome, this feature simply doesn't work, which is probably the easiest way to avoid the issue, however you can disable the feature here:
You can change the default browser to run the website in just to the left.
In terms of Response.Redirect, I think that's been well covered, you should use return Redirect() instead, however your code needs to be refactored to allow for that.
Assuming that method is a helper method which is required to be separate from the controller itself, there are a couple of main approaches to doing what you're trying to to do.
1) Magic Values
This could include "redirect1" or also commonly null, and would look something like:
public ActionResult MyAction
{
string data = ProcessString("some data");
if (data == null) { return Redirect("google.com"); }
}
public string ProcessString(string input)
{
if (condition) { return null; }
string output = input + "!"; // or whatever you need to do!
return input;
}
2) Handle via exceptions
Assuming the problem is that the data is in some way bad, and you want to redirect away because you cant process it, Exception handling is most likely the way to go. It also allows for different types of exceptions to be raised by a single method and handled independently without having magic values which then can't be used as normal data.
public ActionResult MyAction
{
string data; // remember this will be null, not "" by default
try
{
data = ProcessString("some data");
}
catch (OwlMisalignedException ex)
{
return RedirectToAction("Index", "Error", new { exData = ex.Code });
}
// proceed with controller as normal
}
public string ProcessString(string input)
{
if (condition)
{
throw new OwlMisalignedException(1234);
// this is (obviously) a made up exception with a Code property
// as an example of passing the error code back up to an error
// handling page, for example.
}
string output = input + "!"; // or whatever you need to do!
return input;
}
By using that approach you can effectively add extra return states to methods without having to fiddle with your return type or create loads of magic values.
Don't use throw Exception - either use one of the more specific types ArgumentException and ArgumentNullException will probably come in handy, or create your own types if needs be.
You'll find info on creating your own Exception types on here easily enough.
i have the following Action method that return an _error partial view in case an Exception occur:-
[AcceptVerbs(HttpVerbs.Post)]
public PartialViewResult Register(string id, int classid) {
try
{
Thread.Sleep(3000);
User user = r.FindUser(id);
Users_Classes uc = new Users_Classes();
uc.AddedDate = DateTime.Now;
uc.ClassID = classid;
user.Users_Classes.Add(uc);
r.Save();
ViewBag.classid = classid;
return PartialView("_usersearch2", uc);
}
catch (DataException ex)
{
return PartialView("_error");
}
and the following _error partial view:-
<script type="text/javascript">
alert('The user might have been already Assinged, Search Again to get the latest users');
</script>
The above approach is working fine, but does it consider a bad design to return a partial view to display only an alert ? and is there a better way to do this?
The problem is you are now tying your implementation to your user interface. The Controller suddenly decides how an error message should appear on the client.
What if you want to change it from an alert to displaying a red border around a text input with some description next to it?
Determining how something should be displayed is up to your view. Your controller should only return status codes and then your view should decide what to do.
Instead of returning inline js you should have error handling code on your client side within a js library. Rather than returning the hole js only return the message.
In general, I'd say yes. But, sometimes a bad design is just what the doctor ordered ;)
There's a Controller instance method called Javascript that I use to return executable javascript from my controller, on very limited occasions, when taking the time to do it the "right" way isn't feasible:
[AcceptVerbs(HttpVerbs.Post)]
public PartialViewResult Register(string id, int classid)
{
try
{
... stuff
}
catch (DataException ex)
{
return Javascript("alert('The user might have been already Assinged, Search Again to get the latest users');");
}
}
The fact that something like this exists gives me solace that I'm not completely breaking the law.. unless I'm using it wrong, which I probably am.