Hello I am new in mvc so I have a problem during the DB update. I have table in database which column is defined as a unique key that means I don't want to same data in that column but at the time of entering same data my data access layer class generates an exception called DbUpdate exception. I just want to handle this exception by sending a message "Your given data is already exists".. Please help me. Thanx in advance.
Generally, the idea is you want to raise a custom exception which make sense to each layer. The reason for this is because you want to keep your DAL abstract, for example, in your DAL you would catch this particular exception (DbUpdateException) and raise your own custom exception e.g.
try
{
...
myContext.SaveChanges();
}
catch (DbUpdateException ex)
{
throw new DuplicateDataException("Data already exists");
}
Then in your business layer, if you want to further abstract you could throw a domain exception
try
{
dataStore.Save(new Entity { ... });
}
catch (DuplicateDataException ex)
{
throw new DomainException(ex.Message);
}
Then finally in your controller, pass the error to the view
[HttpPost]
public ActionResult SomeAction(SomeModel model)
{
try
{
myDomain.Save(model);
return View("Success", model);
}
catch (DomainException ex)
{
return View("Error", ex.Message);
}
}
The example is completely fictitious of course and may or may not apply to your specific code-base, however, the goal is to demonstrate how the exception will effectively "bubble-up" from your DAL layer back to your UI.
I am placing particular emphasis on using custom exceptions simply because it provides you with a nice clean abstraction.
Related
I have this simple controller, whose Get method is called with ajax to look up zipcodes via an Entity Framework repository.
[Authorize]
public class ZipCodesApiController : AppApiController
{
public ZipCode Get(string zipCode)
{
return unitOfWork.ZipCodeRepository
.Get(x => x.Zip == zipCode)
.FirstOrDefault();
}
}
In production, my logs show that System.OperationCanceledException: The operation was canceled. is thrown quite often. I think what's going on is that users are viewing an address detail page, but navigating away or closing their browser before the ajax zipcode lookup returns. I guess IIS is telling my controller that they are no longer connected, and the .NET framework throws an exception?
This seems harmless, but it also seems like a bad idea to wrap the call to ZipCodeRepository in a try and have an empty OperationCanceledException catch clause.
I've googled the error and it seems to come up quite a bit in parallel programming, which is not something I am particularly familiar with.
What is an appropriate way to handle this exception? I think it's safe to ignore, but am I wrong about that, and the Entity Framework should be alerted so that it can clean something up (my AppApiController does have a dispose method at least)?
I get the same exceptions in my web API application, however i can catch them with the Application_Error method in Global.asax.cs
protected void Application_Error(object sender, EventArgs e)
{
Exception exception = Server.GetLastError();
Response.Clear();
OperationCanceledException httpException = exception as OperationCanceledException;
if (httpException != null)
{
var token = httpException.CancellationToken;
if (token.IsCancellationRequested)
{
// clear error on server
Server.ClearError();
Request.Abort();
}
}
}
I don't know if that is right.
So I have a method in my service, which I will call from a controller:
public void SendMessage(Message message) {
message.Property = "Random";
try {
// try some insert logic
}
catch (Exception) {
// if it fails undo some stuff
// return the errors
throw;
}
// if there are no errors on the return the operation was a success
// but how do I get the Service generated data?
}
Edit:
So the question isn't really about getting my code to work it's a problem I have with the Repository Pattern whilst using a Service Layer as a 'go between' for communication between the DAL and Presentation
So I have a separate assembly called DataLibrary.
The DataLibrary has my models (Message), my repositories and Services (MessageService)
In my MVC site I would typically have a controller, with CRUD functionality. It would look something like this:
public ActionResult Create(Message message) {
if(ModelState.IsValid) {
db.insert(message);
}
Return View(message);
}
But by using the Repository Pattern, with a service layer for communication I have this instead:
public ActionResult Create(MessageCreateModel message) {
if(ModelState.IsValid) {
MessageService.SendMessage(message.ToDTO());
}
Return View(message);
}
How do I know that the operation was successful or unsuccessful and for what reason?
How do I retrieve the populated data from the service's business logic at the same time as the above?
And how do I achieve both of these two above while sticking as close as possible to MVC design pattern / spearation of concerns for extensibility?
First of all, why do you go through as service if it's just delegating the work to your repository? If you have implemented your repository properly (i.e. being a complete abstraction) there is no need to use the service. Simply call the repository directly from your controller. You can read more about the repository pattern in my blog.
But that doesn't really adress the issue.
So how do you handle errors? When it comes to exceptions: Simply do not catch it ;) Exceptions are after all exceptions and is not something that you typically can handle to deliver the expected result.
As we are talking about the data layer that usually means a stable database engine where it's expected that the read/write will succeed. Hence there is no need for any other error handling than using exceptions.
In ASP.NET MVC you can handle transactions with an attribute and use try/catch to fill the model state as shown here:
[HttpPost, Transactional]
public virtual ActionResult Create(CreateModel model)
{
if (!ModelState.IsValid)
return View(model);
try
{
model.Category = model.Category ?? "Allmänt";
var instruction = new Instruction(CurrentUser);
Mapper.Map(model, instruction);
_repository.Save(instruction);
return RedirectToAction("Details", new {id = instruction.Id});
}
catch (Exception err)
{
// Adds an error to prevent commit.
ModelState.AddModelError("", err.Message);
Logger.Error("Failed to save instruction for app " + CurrentApplication, err);
return View(model);
}
}
You really didn't provide enough information about your architecture is structured to answer this question. However, if you want to get a value back from the SendMessage method, adding a return value instead of void is a good place to start.
I think you should first decide how are you going to design your architecture. Are you go with service oriented, if so your service methods have to be return something for inform controllers. So think your service layer like a border of a country, and the other country's borders are controllers. And you have to let trade these two countries. This can be done with return object which contains return data and also service errors and so on.
If you only want to put your some business logic into your service layer then you probably dont need independent layers. Just some loose coupling is enough for you. So you can return basic clr objects or domain objects or application objects. In a very basic example like this:
//AService service method
public AnEntity ServiceMethod(AFilterViewModel aFilter)
{
//do some validation
try
{
//some transactional operations
}
catch
{
//do some log and rollback it...
throw;
}
var anEntity = _aRepository.GetSomeEntity(x=> x.Something == aFilter.Something);
return anEntity;
}
//controller method
public ActionResult GetSomething(AFilterViewModel aFilter)
{
try
{
var entity = _aService.ServiceMethod(aFilter);
AViewModel model = MapToView(entity);
return View(model);
}
catch
{
return RedirectToAction("Error");
}
}
As you see above the controller and service layer methods can share each others objects. They have boundaries to each other and they coupled. But your architecture decides how much they coupled.
You can also do these mappings one way only. Something like service to Controller only or Controller to service only. If you dont want to use your viewmodel in service layer, you should always do mappings in service layer. Otherwise do your object mapping in controllers. And also dont forgot to put your viewmodel's into another library, its very important. These are something like "value objects".
I was trying out the ToDo sample and ran into an unhandled Excaption while trying out the Concurrency Handling.
The dataservice.js contains these lines in saveFailed(error) method:
if (detail && detail.ExceptionType.indexOf('OptimisticConcurrencyException') !== -1) {
// Concurrency error
reason =
"Another user, perhaps the server, may have deleted one or all of the todos.";
manager.rejectChanges(); // DEMO ONLY: discard all pending changes
}
The client never gets to this point due to an unhandled OptimisticConcurrencyException in:
[HttpPost]
public SaveResult SaveChanges(JObject saveBundle) {
return _contextProvider.SaveChanges(saveBundle);
}
I was trying to catch this and return the Exception which was kind of stupid as the Exception is not of type SaveResult. Is this a bug or am i missing an configuration somewhere?
Greets
Any server side errors should be returned to the promise.fail handler. i.e.
em.saveChanges().then(function(saveResult) {
// normal path
}).fail(function(error) {
// your concurrency exception message will be part of the error object.
});
Error on my side here... Clicking 'Continue' on the Exception Windows in VS the javascript handler is executed.
I have a controller action in my project that has a situation where it needs to display an error message to the user under certain scenarios. This action occurs in a POST:
[HttpPost]
public ActionResult DoSomeAction() {
if( someCondition )
return RedirectToAction("SomeActionError");
return RedirectToAction("Index");
}
public ActionResult SomeActionError() {
return View();
}
Currently I have it set up so that it will redirect to an error controller action. I'm not really fond of this approach because in the URL they see /SomeActionError and it also means that the user can directly navigate to this URL.
Is it a bad design/approach to put some flag in TempData and redirect to another controller that checks for the TempData error flag?
Example:
[HttpPost]
public ActionResult DoSomeAction() {
if( someCondition ) {
TempData["DoSomeActionError"] = true;
}
return RedirectToAction("Index");
}
public ActionResult Index() {
// check for error
if( TempData["DoSomeActionError"] ) {
return View("SomeActionError");
}
}
Is this a bad idea? Is there another approach that does something similar (doesn't allow the user to directly navigate to the error action)? I don't want to return the View on the POST action because I don't want them to refresh and cause another POST.
TempData is not per se a bad concept. TempData is for transporting an information to some consumer that reads that information and the information should vanish after it's been read.
The way your're using TempData is odd. A more elegant implementation for your requirements (you should show an error message) is to implement an equivalent to the rails flash concept and don't redirect to an error page but display an error message in your index view. Something like a red banner that says "The record could not be saved".
This question shows a nice flash implementation including the view stuff (not the accepted answer but the answer by #jim)
using tempdata in mvc is not a good approach.
If i were you i'll do as following:
[HttpPost]
public ActionResult DoSomeAction() {
if( someCondition ) {
return RedirectToAction("Index", new{error=true}
}
return RedirectToAction("Index");
}
public ActionResult Index(bool? error) {
// check for error
if(error?? false ) {
return View("SomeActionError");
}
}
While I don't agree TempData is always bad (I find it great for status messages I absolutely don't want passed on the url such as "record saved", I think in your case there may be a better option.
First you don't want an error page to be accessible - may I ask why?
To do a redirect when an error happens only to redirect again is a bit odd. I would throw the exception and handle that exception by your error view. MVC automatically adds the [HandleError] attribute as a global filter, so throw your exception (a custom type if necessary) and handle it in your error page as you see fit since you can access exception details there and it doesn't require a redirect.
Hi i'm new to MVC and EF so this may be a really simple question but what is the best way to prevent the user from trying to enter duplicate records?
I have a simple look up table with one column which is the primary key. I'm creating a maintenance screen so admins can add extra items to the look up list. My controller looks like :
public ActionResult Index(string NewRow)
{
try
{
CaseType t = new CaseType { ID = NewRow };
if (ModelState.IsValid)
{
UOW.CaseTypes.Add(t);
UOW.Save();
}
}
catch (Exception ex)
{
ModelState.AddModelError("", ex.Message);
}
return View(UOW.CaseTypes.All());
}
Which stops the duplicate records and stops the yellow screen of death but the message displayed is : "An error occurred while updating the entries. See the inner exception for details." which is no good for the users.
I was just wondering if there is a better way to catch the error.
For show validation error I use something like this:
MainEmail it's property from ViewModel
var mod = ModelState.First(c => c.Key == "MainEmail"); // this
mod.Value.Errors.Add("Row's shouldn't duplicates."); // this
if (ModelState.IsValid)
{
return RedirectToAction("Details");
}
return View(client);
Error will show's in this field in view:
<div class="editor-label">
#Html.LabelFor(model => model.MainEmail)
</div>
And for future, you must hide your error screen! You need to display a custom error page:
If you use asp-mvc-3, add to web.config such string:
<system.web>
<customErrors mode="On" defaultRedirect="~/Error" />
...
And users will have /Shared/Error.cshtml page insted of page with exception message (which can show sequrity data).
ADD
About unique constraint creation was discussed here
Unique Constraint in Entity Framework Code First
than you can check about records duplication with your try code.
In my application I use code first and don't add unique constraint because it's lead to low testability. In that case use simple Find before saving changes.
First aproach is little bit faster.
Approach two is grow up testability.
If you want to get the inner exception you can do like this,
catch (Exception ex)
{
while(ex.InnerException!=null){
ex=ex.InnerException;
}
ModelState.AddModelError("", ex.Message);
}
no too sure about the syntax :)