Can not Catch DbUpdateException raised in my repositiry at my controller method - c#

i have the following register action method :-
[AcceptVerbs(HttpVerbs.Post)]
public PartialViewResult Register(string id, int classid) {
try
{
User user = r.FindUser(id);
Users_Classes uc = new Users_Classes();
uc.AddedDate = DateTime.Now;
uc.ClassID = classid;
user.Users_Classes.Add(uc);
repository.Save();
ViewBag.classid = classid;
return PartialView("_usersearch2", uc);
}
catch (System.Data.UpdateException ex)
{
return PartialView("_error");} }
which calls the following Save method inside the repository class:-
public void Save() {
entities1.SaveChanges();
}
I am facing the following two problems wiht the above code:-
incase two system users register the same User at the same class then the following exception will be raised DbUpdateException on the repository.Save(); and the catch (System.Data.UpdateException ex) will not handle it . so how i can force the exception to be passed to my action method?
how i can return an alert box (which indicates that the user might have been already added to this class) if the exception occur, instead of returning PartialView("_error");} ?.
BR

1) As far as I can see, DbUpdateException is not a sub-class of UpdateException, so if you want to catch DbUpdateException you should probably catch that specifically. Alternatively you can catch a DataException which is the base class for both UpdateException and DbUpdateException

Related

ASP.NET WebApi return different object on exception

I am currently developing an API and need to return some objects for the api or an error in case of failure somewhere, mainly because I am dependent on database calls.
Here is some of my code:
public Student GetStudent(string parametr)
{
try
{
// Database call 1
// Database call 2
return new Student();
}
catch (Exception ex)
{
// return new ErrorDetails(ex.message); -- example
return null;
}
}
One of my constraints is that I need to put this API in swagger. I tried with HttpResponse which fits perfectly my needs regarding the coding part, but that does not work with swagger. My web application is not asp.net core.
Any ideas or suggestions on what should I do?
Thanks in advance,
You can use Swagger DataAnnotations and encapusulate the return data to achieve that
First of all create a class to encapsulate the error messages like that
public class Errors
{
public List<string> ErrorMessages { get; set; } = new List<string>();
}
Then use the annotaions like that
For .NET 4.5+ (Fullframework)
[SwaggerResponse(HttpStatusCode.OK, Type = typeof(Student))]
[SwaggerResponse(HttpStatusCode.BadRequest, Type = typeof(Errors))];
public IHttpActionResult GetStudent(string parametr)
{
try
{
// Database call 1
// Database call 2
return Ok(new Student());
}
catch (Exception ex)
{
Errors errors = new Errors();
errors.ErrorMessages.Add(ex.Message);
return Content(HttpStatusCode.BadRequest, errors);
}
}
For .NET Core
[ProducesResponseType(200, Type = typeof(Student))]
[ProducesResponseType(400, Type = typeof(Errors))]
public IActionResult GetStudent(string parametr)
{
try
{
// Database call 1
// Database call 2
return Ok(new Student());
}
catch (Exception ex)
{
Errors errors = new Errors();
errors.ErrorMessages.Add(ex.Message);
return BadRequest(errors);
}
}
Note that the BadRequest is just an example of return, you should always return the correct Http Status Code message, like 404 to not found, 401 to forbidden and so on

Handling errors and success in same format

I am trying to create a more robust method that returns two different object types depending on results.
If the result is negative then return CustomError object, but if the result is positive then return Auto object.
Example below to demonstrate.
AutoService.cs
public class AutoService {
public async Task<object> Create(NewAuto model)
{
var auto = new Auto {
Type = model.Type,
Year = model.Year,
// other parameters
}
try {
await _autoDb.Create(auto);
}
catch (Exception e) {
// return this error object if something broken
return new CustomError { Message = "It is broken" }
}
//return the Auto entity if successful
return auto;
}
}
CustomError.cs
public class CustomError {
public string Message {get;set;}
}
In the current format the when calling Create method i will need to cast the result which brings headaches of its own (cast against CustomError or Auto class for e.g.).
Any advice how i can do this properly?
Why not create a class to represent the result, something like:
class EntityResult<T> {
public EntityResult(T entity) {
Success = true;
Entity = entity;
}
public EntityResult(string error) {
Success = false;
Error = error;
}
bool Success {get; }
T Entity { get; }
string Error { get; }
}
Usage would be like:
public async Task<EntityResult<Auto>> Create(NewAuto model) {
var auto = new Auto {
Type = model.Type,
Year = model.Year,
// other parameters
};
try {
await _autoDb.Create(auto);
return new EntityResult(auto);
} catch (Exception e) {
// return this error object if something broken
return new EntityResult<Auto>("Error goes here");
}
}
I wouldn't use a return type to represent two different results e.g. success and failure. It will make the code hard to understand and, as time goes on, you will (probably) find that the return type will get abused and expanded to contain other (irrelevant?/unnecessary?) information.
Apply the Single Responsibility Principle to the return type:
If the call was successful then return the correct object i.e. Auto
If the call failed (i.e. you caught and exception) then create a custom exception to pass that failure back up the call stack. The name of your exception will make the code clearer than enclosing errors in a generic object.
Also your calling code will be much cleaner (and easier to maintain) if you use exception handling instead of an object with two purposes. Keep it simple.

Bubbling up Update Concurrency Exceptions to view

What is a good way to bubble up a DbUpdateConcurrencyException to the view from the grain?
I'm currently working on an Orlean's prototype that has a custom state that I'm using Entity Framework Core to communicate with the DB and using the optimistic concurrency patterns built into EF Core to manage the concurrency issues.
Where I'm having an issue is that I want to bubble up my Exception from the grain to the view and am not receiving it on the view end.
I'm trying to accomplish this because I want to deal with some of the concurrency issues that are more pressing on the view so that the user can decide or at least be alerted to the issue.
I brought this up on the Orlean's Gitter, but didn't get many ideas from it.
Example of my code for updating:
public Task UpdateUser(User user)
{
//Reason for second try/catch is to bubble the error to controller
try
{
userState = new User
{
Username = this.GetPrimaryKeyString(),
accountType = user.accountType,
FName = user.FName,
LName = user.LName,
RowVersion = user.RowVersion,
CreatedDate = user.CreatedDate
};
UpdateState();
}
catch (DbUpdateConcurrencyException ex)
{
throw ex;
}
return Task.CompletedTask;
}
public Task UpdateState()
{
using (var context = new OrleansContext())
{
context.users.Update(userState);
try
{
context.SaveChanges();
}
catch ( DbUpdateConcurrencyException ex)
{
var entry = ex.Entries.Single();
var clientValues = (User)entry.Entity;
var databaseEntry = entry.GetDatabaseValues();
//Make sure the row wasn't deleted
if(databaseEntry != null)
{
var databaseValues = (User)databaseEntry.ToObject();
if(clientValues.accountType != databaseValues.accountType)
{
//Bubble up the exception to controller for proper handling
throw ex;
}
//Update Row Version to allow update
userState.RowVersion = databaseValues.RowVersion;
context.SaveChanges();
}
}
}
return Task.CompletedTask;
}
I'm open to any suggestions on this as long as it allows the user to be alerted to the Exception and can view their data and the current DB values.
There is a chance that the exception is not being serialized or deserialized correctly. The primary reasons for this could be:
The Exception class does not correctly implement the ISerializable pattern.
The assembly which contains the Exception class is not present on the client, so the client does not understand how to create the Exception type.
In this case, I would lean towards the second reason, because most (but not all!) Exception classes do correctly implement the ISerializable pattern.
In either case, you can catch your exception and turn it into a generic exception.
You could create a helper method to do this using the LogFormatter.PrintException(Exception) method from Orleans to format the exception as a string.
public static void ThrowPlainException(Exception e) =>
throw new Exception(Orleans.Runtime.LogFormatter.PrintException(e));
The solution I came to was to create a custom exception class that serializable add the database values object to it and bubble that up to the views.
[Serializable]
public class UpdateException : Exception
{
public object databaseValues { get; set; }
public UpdateException(object databaseValues)
{
this.databaseValues = databaseValues;
}
public UpdateException(string message, object databaseValues) :base(message)
{
this.databaseValues = databaseValues;
}
}

class that wraps my entity object is not saving

I may be going about this incorrectly but this is my class that I wrap my entity object:
using System;
using System.Linq;
namespace SSS.ServicesConfig.data
{
public partial class GlobalSetting
{
private static GlobalSetting _globalSettings;
public static GlobalSetting GlobalSettings
{
get
{
if (_globalSettings == null)
{
GetGlobalSetting();
}
return _globalSettings;
}
}
private static void GetGlobalSetting()
{
try
{
using (var subEntities = PpsEntities.DefaultConnection())
{
_globalSettings = (from x in subEntities.GlobalSettings
select x).FirstOrDefault();
if (_globalSettings == null)
{
_globalSettings = new GlobalSetting();
_globalSettings.GlobalSettingId = Guid.NewGuid();
_globalSettings.CompanyCode = string.Empty;
_globalSettings.CorporationId = Guid.Empty;
_globalSettings.DefaultBranch = "01";
_globalSettings.SourceId = Guid.Empty;
_globalSettings.TokenId = Guid.Empty;
subEntities.AddToGlobalSettings(_globalSettings);
subEntities.SaveChanges();
}
}
}
catch (Exception ex)
{
Logging.Log("An error occurred.", "GetGlobalSetting", Apps.ServicesConfig, ex);
throw new Exception(string.Format("Unable to retrieve data: [{0}].", ex.Message));
}
}
internal static void SaveGlobalSettings()
{
using (var entities = PpsEntities.DefaultConnection())
{
entities.Attach(_globalSettings);
entities.SaveChanges();
}
}
}
}
I'm trying to make it where they have to go through my class to get the settings record and save it though the same class. This is in a separate project that several other projects are going to import.
My save isn't saving to the database and I see no errors or changes on the record. In this particular table, there is only one record so it's not adding another record either.
Any suggestions?
First your save is not being called after the initial value is assigned to _globalSettings.
Second You should not be trying to change the value with a get accessor. It is bad form.
http://msdn.microsoft.com/en-us/library/w86s7x04.aspx
I recommend that you separate the responsibility of the save to the database to a new method (you could expose the SaveGlobalSettings method by making it public), but if you are determined to obfuscate the save from the user, then I would recommend you remove the save to the database from get accessor of the GlobalSettings property, create a set accessor for the GlobalSettings property, and put the save to the database in the GlobalSettings properties set accessor.
One other note, you are killing your stack trace.
throw new Exception(string.Format("Unable to retrieve data: [{0}].", ex.Message));
You can still catch and log the exception the way that your are doing it, but re-throw the exception like this:
catch (Exception ex)
{
Logging.Log("An error occurred.", "GetGlobalSetting", Apps.ServicesConfig, ex);
throw;
}
This will preserve the original exception.

catch error and return in method result

I have my own wcf service class which should as result return string with "Everything Save Saccesfully" if ok save data. Otherwise I need to return in this string exception.
string SaveData(Stream stream)
{
string error = "";
try
{
//do saving data
error+="Everything Save Saccefully";
return error;
}
catch(Exception ex)
{
throw ex;
}
finally
{
}
}
It is possible to catch errors occurs in try block and return it in error variable ?
Well, the traditional way that you express the error is simply via an exception - not a return value. Lack of exception should imply "everything went correctly". That's the normal idiomatic way of working.
Now, occasionally it's worth having a method which doesn't throw an exception, but instead returns a success status and potentially a separate result via an out parameter. But that's relatively rare - it's usually for things like parsing, where it's entirely normal for it to fail in hard-to-predict ways when nothing's really wrong other than the input data.
In your case, it looks like this should be a void method which simply throws an exception on error.
Normally I would do as suggested by Jon, but if you really don't want to allow any exceptions to bubble up from your service you could encapsulate your success and (any) failure error information in a class structure like this
public class ErrorInfo
{
public string Message {get; set;}
// TODO: Maybe add in other information about the error?
}
public class SaveResult
{
public bool Success { get; set; }
/// <summary>
/// Set to contain error information if Success = false
/// </summary>
public ErrorInfo ErrorInfo { get; set; }
}
And then...
public SaveResult SaveData(Stream stream)
{
SaveResult saveResult = new SaveResult();
string error = "";
try
{
//do saving data
saveResult.Success = true;
}
catch (Exception ex)
{
saveResult.ErrorInfo = new ErrorInfo { Message = ex.Message };
}
}
The downside of this approach is that your caller must check the Success value after calling SaveData. Failure to do so can result in a bug in your code that will only manifest itself if the save fails.
Alternatively, if you don't handle the exception you get to benefit from one of the useful things about structured exception handling: If the caller forgets to explicitly handle any exception then it will bubble up the call stack and either crash the app or get caught by some higher-level error handling code.
Not necessarily ideal, but generally better than your code silently assuming that something succeeded, when in fact it didn't.
You should use Faults for exceptional results in WCF. I do not see idea why you would need exception in string. But if you absolutely need this, just move return statement to the end and set its value in catch block too.
string SaveData(Stream stream)
{
string error = "";
try
{
//do saving data
error+="Everything Save Saccefully";
}
catch(Exception ex)
{
//throw ex; Do not throw, just return its string representation
error+=ex.ToString();
}
finally
{
}
return error;
}
Try this :
string SaveData(Stream stream)
{
string error;
try
{
//do saving data
error ="Everything saved Successfully";
}
catch(Exception ex)
{
error = ex.Message;
}
return error;
}

Categories