Elmah and DbEntityValidationException - entity-framework-4.1

I have setup a project with both Elmah and EF4.1 Code First.
The project is throwing a System.Data.Entity.Validation.DbEntityValidationException, but Elmah is not providing enough detail to determine what validation is failing. All that is logged is:
System.Data.Entity.Validation.DbEntityValidationException: Validation failed for one or more entities. See 'EntityValidationErrors' property for more details.
Is there a way to make Elmah expand and log the EntityValidationErrors property?

List<IUserFeedback> errors = new List<IUserFeedback>();
try
{
_dbContext.SaveChanges();
Updated(this, HasUnsavedChanges);
}
catch (DbEntityValidationException ex)
{
foreach (var x in ex.EntityValidationErrors)
{
foreach (var y in x.ValidationErrors)
{
if (!String.IsNullOrWhiteSpace(y.PropertyName))
errors.Add(new UserFeedback() {
FeedbackFlags = TypeOfUserFeedbackFlags.Error,
Message = String.Format("Unable to save {0} due to an issue with its \"{1}\" value. The error returned was \"{2}\"",x.Entry.Entity, y.PropertyName, y.ErrorMessage)
});
else
errors.Add(new UserFeedback() {
FeedbackFlags = TypeOfUserFeedbackFlags.Error,
Message = String.Format("Unable to save {0} due to the error \"{1}\"", x.Entry, y.ErrorMessage)
});
}
}
}
return errors;

Related

How to override Json.Net model binding exception messages for localization purposes?

I've overridden all model binding messages with translations using ModelBindingMessageProvider.SetValueIsInvalidAccessor and other ModelBindingMessageProvider values to return my custom resource strings.
And then I discovered the sad truth. If my API controller receives the data as JSON, then ModelBindingMessageProvider validation messages are not being used. Instead, Json.Net kicks in and I get something like this in response:
"errors": {
"countryId": [
"Input string '111a' is not a valid number. Path 'countryId', line 3, position 23."
]
},
I looked in GitHub source of Json.Net - indeed, it seems to have such exact error messages defined with line numbers etc.
So, ModelState manages to pull them in instead of using its own ModelBindingMessageProvider messages.
I tried to disable Json.Net error handling:
.AddJsonOptions(options =>
{
...
options.SerializerSettings.Error = delegate (object sender, Newtonsoft.Json.Serialization.ErrorEventArgs args)
{
// ignore them all
args.ErrorContext.Handled = true;
};
})
but it made no difference.
Is there any way to catch these Json deserialization errors and redirect them to ModelBindingMessageProvider, so that my localized messages would work?
Is there any way to catch these Json deserialization errors and
redirect them to ModelBindingMessageProvider, so that my localized
messages would work?
No, model binding and json input are different, model binder is for FromForm, and JsonInputFormatter is for FromBody. They are following different way. You could not custom the error message from ModelBindingMessageProvider.
For JSON, you may implement your own JsonInputFormatter and change the error message like
CustomJsonInputFormatter
public class CustomJsonInputFormatter : JsonInputFormatter
{
public CustomJsonInputFormatter(ILogger<CustomJsonInputFormatter> logger
, JsonSerializerSettings serializerSettings
, ArrayPool<char> charPool
, ObjectPoolProvider objectPoolProvider
, MvcOptions options
, MvcJsonOptions jsonOptions)
: base(logger, serializerSettings, charPool, objectPoolProvider, options, jsonOptions)
{
}
public override async Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context)
{
var result = await base.ReadRequestBodyAsync(context);
foreach (var key in context.ModelState.Keys)
{
for (int i = 0; i < context.ModelState[key].Errors.Count; i++)
{
var error = context.ModelState[key].Errors[i];
context.ModelState[key].Errors.Add($"This is translated error { error.ErrorMessage }");
context.ModelState[key].Errors.Remove(error);
}
}
return result;
}
}
Register CustomJsonInputFormatter
services.AddMvc(options =>
{
var serviceProvider = services.BuildServiceProvider();
var customJsonInputFormatter = new CustomJsonInputFormatter(
serviceProvider.GetRequiredService<ILoggerFactory>().CreateLogger<CustomJsonInputFormatter>(),
serviceProvider.GetRequiredService<IOptions<MvcJsonOptions>>().Value.SerializerSettings,
serviceProvider.GetRequiredService<ArrayPool<char>>(),
serviceProvider.GetRequiredService<ObjectPoolProvider>(),
options,
serviceProvider.GetRequiredService<IOptions<MvcJsonOptions>>().Value
);
options.InputFormatters.Insert(0, customJsonInputFormatter);
}).SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}
Register localized Service into CustomJsonInputFormatter to custom the error message.

Displaying Toaster Errors for Bad Http Requests

I am trying to catch an error thrown by my Web API in Angular, and I want to display a user-friendly error message in certain cases. How would I access the string "PE and Owner Signature must be attached for a status of Submitted", given the response body below?
{
"data": {
"model.WorkflowStepId": [
"PE and Owner Signature must be attached for a status of Submitted"
]
},
"exceptionType": "FieldValidation"
}
This is what I have so far, but I'm stuck since I am currently only displaying the string "model.WorkflowSetId".
this.spinner = this.certService.updateCert(this.damId, this.certId, this.model)
.subscribe(response => {
...
},
(errorRes: HttpErrorResponse) => {
if (errorRes.error && errorRes.error.exceptionType === 'FieldValidation') {
const errors = errorRes.error.data;
for(let error in errors)
this.notificationService.error(error);
} else {
console.log(errorRes);
this.notificationService.error('An unknown error has occurred. Please try again.');
}
});
You may simply do:
if (errorRes.error && errorRes.error.exceptionType === 'FieldValidation') {
this.notificationService.error(errorRes.error.data.model.WorkflowStepId[0]);
}
So it turns out that "model.WorkflowStepId" was actually a string. To capture it and other types of validation errors I was able to loop through bad requests, build a string that grouped the same types of field validation errors into single messages, and display those messages to the user using the toaster.
if (errorRes.error && errorRes.error.exceptionType === 'FieldValidation') {
for (var key in errorRes.error.data) {
for (var i = 0; i < errorRes.error.data[key].length; i++) {
errorStr += (errorRes.error.data[key][i]);
errorStr += ". ";
}
this.notificationService.error(errorStr);
}
}

Yii2 isnewrecord generates exception

In yii2 set-up I have multiple models - one being one to many with repeat fields in form where I can edit fieldset or add new records.
but I am facing issue of duplicate key error.
To overcome the same I am trying this code:
try{
$userchild->save();
}
catch(\Exception $e){
$userchild->isNewRecord = false;
$usrchild->save();
}
but I am getting the exception:
Unknown Method – yii\base\UnknownMethodException
Calling unknown method: app\controllers\UserController::setIsNewRecord()
What I am missing here?
update with more code:
if ($model->load(Yii::$app->request->post()) && $profile->load(Yii::$app->request->post()) && $billinginfo->load(Yii::$app->request->post()) ) {
$model->username = $model->email;
$model->save();
$profile->save();
$billinginfo->save();
if (!empty($_POST['UserChildren']) && !is_null($_POST['UserChildren'])) {
foreach($_POST['UserChildren'] as $rows){
$userchild = New UserChildren;
$userchild->user_id = $model->id;
$userchild->id =$rows['id'];
$userchild->attributes=$rows;
try{
$userchild->save();
} catch(\Exception $e){
$userchild->setIsNewRecord(false);
$usrchild->save();
}
}
}
Now I am getting the error:
Unknown Property – yii\base\UnknownPropertyException
Getting unknown property: app\models\UserChildren::_attributes
if you want assigng the attributes you should use
$userchild->setAttributes($rows, TRUE);
https://www.yiiframework.com/doc/api/2.0/yii-base-model#$attributes-detail

EWS managed API AutoDiscover is running very slow

I'm using EWS API for consuming outlook 365 mail service.
When I'm performing any mail operation it's running slow.
I have written the code mentioned below:
ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2013_SP1);
service.Credentials = new WebCredentials("usernm", "pwd");
service.EnableScpLookup = false;
service.AutodiscoverUrl("user",RedirectionUrlValidationCallback);
That last line takes 16 seconds before the connection is successful.
Is there any way to make the performance faster?
Hard to say...not saying this is the answer
but try this and let me know.
I see a difference in that i dont pass RedirectionUrlValidationCallback in the autoDiscoverUrl and I don't set EnableScpLookup flag, dont know what that is for. let me know
public ExchangeService GetService( string autoDiscoverEmailAddress, string authEmailAddress,string authEmailPassword, string domain = null, ExchangeVersion verion = ExchangeVersion.Exchange2010_SP2 )
{
try
{
ServicePointManager.ServerCertificateValidationCallback = CertificateValidationCallBack;
ExchangeService svc = new ExchangeService(verion);
//svc.UseDefaultCredentials = true;
if (!string.IsNullOrWhiteSpace(domain))
{
svc.Credentials = new WebCredentials(authEmailAddress, authEmailPassword, domain);
}
else
{
svc.Credentials = new WebCredentials(authEmailAddress, authEmailPassword);
}
svc.AutodiscoverUrl(autoDiscoverEmailAddress);
return svc;
}
catch (Exception)
{
throw;
}
}

Silex: error handlers for specific exception types

It it possible in Silex to use an error handler based on what exception is thrown?
I know this is possible with a single exception handler and a switch statement on the classname of the thrown exception but to me it seems the "Silex way" is cleaner, yet doesn't work.
This is how I would expect it to work
<?php
// Handle access denied errors
$app->error(function (\App\Rest\Exception\AccessDenied $e) {
$message = $e->getMessage() ?: 'Access denied!';
return new Response($message, 403);
});
// Handle Resource not found errors
$app->error(function (\App\Rest\Exception\ResourceNotFound $e) {
$message = $e->getMessage() ?: 'Resource not found!';
return new Response($message, 404);
});
// Handle other exception as 500 errors
$app->error(function (\Exception $e, $code) {
return new Response($e->getMessage(), $code);
});
Problem is that when I throw a ResourceNotFound exception in my controller, the errorhandler tied to AccessDenied is executed
Catchable fatal error: Argument 1 passed to {closure}() must be an instance of App\Rest\Exception\AccessDenied, instance of App\Rest\Exception\ResourceNotFound given
Is this achievable in another way or should I just stuff everything in the handler that works with generic Exceptions and switch on the type of exception thrown?
PS: i'm aware of the $app->abort() method but prefer working with exceptions
EDIT: This feature has now made it into Silex core!
This is currently not possible. Right now you'd have to either have a single handler with a switch statement, or many handlers with an if ($e instanceof MyException) each.
I do like the idea though, and it should be possible to implement it by using reflection. It would be awesome if you could create a new ticket on the tracker, or even work on a patch, if you're interested.
Cheers!
Another solution that I use in my projects:
class ProcessCallbackException extends Exception
{
public function __construct(\Closure $callback, $message = "", Exception $previous = null)
{
parent::__construct($message, 0, $previous);
$this->callback = $callback;
}
public $callback;
}
class AccessDeniedException extends ProcessCallbackException
{
public function __construct($message = null)
{
$f = function() {
return app()->redirect('/login');
};
parent::__construct($f, $message);
}
}
# Handle your special errors
$app->error(function (\Exception $e, $code) {
if ($e instanceof ProcessCallbackException)
{
/** #var ProcessCallbackException $callbackException */
$callbackException = $e;
return call_user_func($callbackException->callback);
}
else
return null;
});