MVC 4 - Exception Helper - asp.net-mvc-4

In mvc 4 (but I think in all mvc version) I need to intercept a DbEntityValidationException.
In this phase I need to show the error that is in this object, in a simple log.
In the catch, I have this code:
foreach (var eve in EventityValidationErrors)
{
foreach(var ve in eve.ValidationErros)
{
Console.Writeline(ve.PropertyName,ve.ErrorMessage)
}
}
and it's very useful.
Now, my work is try to show this Exception info (only in develop phase) in a View.
Does someone know if there is a rapid way to do it? (ideally with external nuget component)

Elmah has a nuget package and gives a rapid way to present detailed errors.
You would need to change your catch just a little. That is catch your exception, create a new exception, which includes your data, and then throw this exception and let Elmah deal with it.
catch(DbEntityValidationException dbEx)
{
var sb = new StringBuilder();
foreach (var eve in dbEx.EntityValidationErrors)
{
foreach(var ve in eve.ValidationErrors)
{
sb.Append(ve.PropertyName);
sb.Append(ve.ErrorMessage); //format to your needs
}
}
var detailedException = new Exception(sb.ToString(), dbEx)
}
There is plenty of documentation on how to setup Elmah to catch all unhandled mvc exceptions.

Related

Clean Architecture UI layer containing Entity Framework Core Reference

I'm working on a .Net 5 project I have used Clean Architecture pattern . When I handle concurrency I need to add a EFCore reference to the Web project as below. Is that correct to add EFCore reference to the Web project in Clean Architecture pattern. DbUpdateConcurrencyException Need EFCore reference.
public async Task<IActionResult> EditSubmit(EditProductViewModel editProductViewModel)
{
try
{
if (!ModelState.IsValid)
{
return View("../Product/Edit", editProductViewModel);
}
await _productService.UpdateProduct(editProductViewModel);
ModelState.Clear();
return View("../Product/Edit", new EditProductViewModel());
}
catch (DbUpdateConcurrencyException ex)
{
string message = "Product has been changed by another user please go to Product List";
_log.LogError(message + ":" + ex.ToString());
return View("../Product/Edit", editProductViewModel);
}
catch (Exception ex)
{
string message = "Product update failed";
_log.LogError(message + ":" + ex.ToString());
return View("../Product/Edit", editProductViewModel);
}
}
My understanding is that this is not correct for Clean Architecture. I believe you should create a custom Exception, perhaps in your Application layer, and throw that up to the UI/API layer instead. If you keep a dependency on the EF Core package in the API, in the event that you ever decide to change your persistence mechanism (e.g. not using Entity Framework), you would have to also change your UI/API layer with 1) a new package reference, and 2) a new exception type.

.Net Core 3.1 Json serialization of EdmModel

I encountered an issue but I'm not sure if it's a bug or a known behaviour (can't find anything).
So we use the Orleans project and in one of our grain in the state we store an EdmModel. The issue is that Orleans raise an error during the serialization of the EdmModel (using Newtonsoft). So I was like, ok, let's find out what I've done wrong when buidling the Edm (it's constructed "by hand" because we don't have the models (created by users)).
To check what was happening I try to serialize the Edm myself and encountered the following :
Self referencing loop detected for property 'DeclaringType' with type 'Microsoft.OData.Edm.EdmEntityType'. Path 'SchemaElements[0].DeclaredKey[0]'.
So I was like, ok. I've done something bad and it's why the serialisation is not working, But after commenting my code to narrow the issue, I was left with the following :
var model = new EdmModel();
try
{
var test = JsonConvert.SerializeObject(model);
}
catch (Exception e)
{
var poney = 1;
}
try
{
var test = JsonConvert.SerializeObject(model, new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore });
}
catch (Exception e)
{
var poney = 2;
}
And it's still raising an error.
Self referencing loop detected for property 'Model' with type 'Microsoft.OData.Edm.Csdl.CsdlSemantics.CsdlSemanticsModel'. Path 'ReferencedModels[1].SchemaElements[0]'
And for the second try catch an OutOfMemory.
So I'm asking if there is a way to serialize an EdmModel to Json ? Because if it is what we can do is storing the EdmModel as string in the state of the grain and making serializaion/deserialization in the Getter/Settter.
Or maybe with Xml?
Thanks a lot for the help and the inputs :)

ABP: Rebuilding Localization Sources from Custom Provider

I am using ABP v4.9.0 (.NET CORE 2.2) with angular client
I built some custom localization providers. These providers get translation dictionaries from an external API.
I add localization sources on startup with these providers.
var customProvider = new CustomLocalizationProvider(...);
var localizationSource = new DictionaryBasedLocalizationSource("SOURCENAME", customProvider );
config.Localization.Sources.Add(localizationSource );
On startup, the providers InitializeDictionaries() is called and localization dictionaries are built.
So far, so good, working as intended.
Now i'd like to manually Reload these translations on demand, but I can't make this working.
Here is what I tried.
Here I trigger the re-synchronize of the language ressources:
foreach (var localizationSource in _localizationConfiguration.Sources)
{
try
{
localizationSource.Initialize(_localizationConfiguration, _iocResolver);
}
catch (Exception e)
{
Logger.Warn($"Could not get Localization Data for source '{localizationSource.Name}'", e);
}
}
In the custom provider, I first clear the Dictionaries
public class CustomLocalizationProvider : LocalizationDictionaryProviderBase
{
protected int IterationNo = 0;
protected override void InitializeDictionaries()
{
Dictionaries.Clear();
IterationNo += 1;
var deDict = new LocalizationDictionary(new CultureInfo("de-DE"));
deDict["HelloWorld"] = $"Hallo Welt Nummer {IterationNo}";
Dictionaries.Add("de-DE", deDict);
var enDict = new LocalizationDictionary(new CultureInfo("en"));
enDict["HelloWorld"] = $"Hello World number {IterationNo}";
Dictionaries.Add("en", enDict);
}
}
The provider is executed again as expected.
But when I eventually use the localization clientside (angular), I still get the original translations.
What am I missing?
Thanks for the help.
In the meanwhile I had to go for another approach.
I am now using a XmlEmbeddedFileLocalizationDictionaryProvider wrapped by a MultiTenantLocalizationDictionaryProvider.
This way, I am using db-localizations with xml-sources as fallback
Then I manually load the ressources from my API in some appservice. These localizations are then updated in the database by using LanguageTextManager.UpdateStringAsync().

nHibernate session per request and exception management

I have a scenario similar to this:
Asp.NET MVC 4 website using nHibernate Session Per Request.
The session is injected using Ninject onto a Repository with the Get and Save methods.
There are a lot of articles talking about Session Per Request and saying that is the way to do things on a web application.
But i'm having problems implementing logic like this one:
Read Data From Database
Alter Entity information
Save to Database
Read another entity
Alter entity
Save ... but an EXCEPTION OCCURS
I want to show my view with a message to the user. But i have also to refresh the resulting web page,
so i have also to read some information from the database.
According to nHibernate documentation, the session with the exception must be discarded Documentation Here
But i can't find any articles about the best way to proceed here.
What's the best approach for this situation?. I will have to inject a new Session to my repository object?.
Thanks.
You can create a new session from the SessionFactory property of the original session. You can access the original session object by either exposing it in the repository class or injecting it into the controller. Then you can create a new repository with the new session.
I do this in some of my Actions where I expect unique key violations to occur and I have to reload lookup data in the model. Here's an example:
public ActionResult Create(MeasuresEditView model)
{
if (ModelState.IsValid)
{
using (var txn = _session.BeginTransaction())
{
try
{
var measure = new Measure { Code = model.Code };
_session.Save(measure);
txn.Commit();
return RedirectToAction("Index");
}
catch (UniqueKeyException)
{
txn.Rollback();
var msg = string.Format("A measure with the code '{0}' already exists, please enter a different code or cancel.", model.Code);
ModelState.AddModelError("Code", msg);
}
catch (Exception ex)
{
if (txn.IsActive)
{
txn.Rollback();
}
log.Error("Create", ex);
throw;
}
}
}
// have to rebuild selectlist on post in new txn in case it was rolled back
using (var session = _session.SessionFactory.OpenSession())
using (var txn = session.BeginTransaction())
{
SetProductGroupSelectList(session, model, manualId);
txn.Commit();
}
return View(model);
}

Creating an SPListItem in a WCF service deployed to SharePoint

i have the following method in a WCF service, that has been deployed to SharePoint using Shail Malik's guide:
[OperationContract]
public string AddItem(string itemTitle, Guid? idOfListToUse)
{
using (var portal = new SPSite(SPContext.Current.Site.Url, SPContext.Current.Site.SystemAccount.UserToken))
{
using (var web = portal.OpenWeb())
{
Guid listId;
web.AllowUnsafeUpdates = true;
if (idOfListToUse != null && idOfListToUse.Value != new Guid())
{
listId = idOfListToUse.Value;
}
else
{
try
{
listId = new Guid(web.Properties[PropertyBagKeys.TagsList]);
}
catch (Exception ex)
{
throw new MyException("No List Id for the tag list (default list) has been found!", ex);
}
}
var list = web.Lists[listId];
string title = "";
SPSecurity.RunWithElevatedPrivileges(delegate{
var newItem = list.Items.Add();
newItem["Title"] = itemTitle;
newItem.Update();
title = newItem.Title;
});
web.AllowUnsafeUpdates = false;
return title;
}
}
}
When the method gets called from Javascript (using Rick Strahl's excellent ServiceProxy.js) it fails and it does so on newItem.Update() because of ValidateFormDigest().
Here's the kicker though, when I step through the code it works! No exceptions at all!
Ok, found the answer (there's 2 even :-D)
First, the dirty one:
Set FormDigestValidatedProperty in the context:
HttpContext.Current.Items["FormDigestValidated"] = true;
Second, the slightly less dirty version (basically leaving the way open for XSS attacks, but this is an intranet anyway)
The answer
I don't think you can access 'list' as it was created outside the elevated code block.
http://blogs.pointbridge.com/Blogs/herzog_daniel/Pages/Post.aspx?_ID=8
I'm guessing when you are stepping though the entire process is in admin mode so all are elevated.
Colin, it's a really bad idea to try to access HttpContext (likewise SPContext) inside a WCF service. See here: MSDN: WCF Services and ASP.NET
From the article:
HttpContext: Current is always null
when accessed from within a WCF
service.
It's likely this is the cause of your problem.
EDIT: I notice that you're trying to use SPContext to get the url of the site collection. I didn't find a good solution to this either so I just send the url of the target site collection as a parameter to the service call. Not the most optimal solution but I couldn't think of a better way. Also, if you need to check authentication/identities, etc use ServiceSecurityContext.Current.