How can I hide System.Exception errors on .NET Core? - .net-core

I try to improve myself with .NET Web API now and I am trying to return a custom error in Swagger. But when returning this custom error, I can see the error is on which line. How can I do to prevent this?
public async Task<BookCreateDTO> CreateBook(BookCreateDTO bookCreateDto)
{
if (await _context.Books.AnyAsync(x => x.Name == bookCreateDto.Name))
{
throw new BookExistException("Book already exist");
}
var book= _mapper.Map<Book>(bookCreateDto);
_context.Books.Add(book);
await _context.SaveChangesAsync();
return book;
}
What should I do to see only this exception message in the Swagger response?
Thank you for your help.

Exceptions should be exceptional: Don't throw exceptions for non-exceptional errors.
I don't recommend specifying your web-service's response DTO type in the C# action method return type because it limits your expressiveness (as you're discovering).
Instead use IActionResult or ActionResult<T> to document the default (i.e. HTTP 2xx) response type and then list error DTO types in [ProducesResponseType] attributes with their corresponding HTTP status codes.
This also means that each response status code should only be associated with a single DTO type.
While Swagger is not expressive enough to allow you to say "if the response status is HTTP 200 then the response body/DTO is one-of DtoFoo, DtoBar, DtoQux", in-practice a well-designed web-service API should not exhibit that kind of response DTO polymorphism.
And if it didn't, how else is a client supposed to know what the type is just from the HTTP headers? (Well, you could put the full DTO type-name in a custom HTTP response header, but that introduces other problems...)
For error conditions, add the errors to ModelState (with the Key, if possible) and let ASP.NET Core handle the rest for you with ProblemDetails.
If you do throw an exception, then ASP.NET Core can be configured to automatically render it as a ProblemDetails - or it can show the DeveloperExceptionPage - or something else entirely.
I note that a good reason to not throw an exception inside a Controller for non-exceptional exceptions is because your logging framework may choose to log more details about unhandled exceptions in ASP.NET Core's pipeline, which would result in useless extraneous entries in your logs that make it harder to find "real" exceptions that you need to fix.
Document the DTOs used, and their corresponding HTTP status codes, with [ProducesResponseType]: this is very useful when using Swagger/NSwag to generate online documentation and client libraries.
Also: do not use EF entity types as DTOs or ViewModels.
Reason 1: When the response (with EF entity objects) is serialized, entities with lazy-loaded properties will cause your entire database object-graph to be serialized (because the JSON serializer will traverse every property of every object).
Reason 2: Security! If you directly accept an EF entity as an input request body DTO or HTML form model then users/visitors can set properties arbitrarily, e.g. POST /users with { accessLevel: 'superAdmin' }, for example. While you can exclude or restrict which properties of an object can be set by a request it just adds to your project's maintenance workload (as it's another non-local, manually-written, list or definition in your program you need to ensure is kept in-sync with everything else.
Reason 3: Self-documenting intent: an entity-type is for in-proc state, not as a communications contract.
Reason 4: the members of an entity-type are never exactly what you'll want to expose in a DTO.
For example, your User entity will have a Byte[] PasswordHash and Byte[] PasswordSalt properties (I hope...), and obviously those two properties must never be exposed; but in a User DTO for editing a user you might want different members, like NewPassword and ConfirmPassword - which don't map to DB columns at all.
Reason 5: On a related note to Reason 4, using Entity classes as DTOs automatically binds the exact design of your web-service API to your database model.
Supposing that one day you absolutely need to make changes to your database design: perhaps someone told you the business requirements changed; that's normal and happens all the time.
Supposing the DB design change was from allowing only 1 address per customer (because the street addresses were being stored in the same table as customers) to allowing customers to have many addresses (i.e. the street-address columns are moved to a different table)...
...so you make the DB changes, run the migration script, and deploy to production - but suddenly all of your web-service clients stop working because they all assumed your Customer object had inline Street address fields but now they're missing (because your Customer EF entity types' don't have street-address columns anymore, that's over in the CustomerAddress entity class).
If you had been using a dedicated DTO type specifically for Customer objects then during the process of updating the design of the application you would have noticed builds breaking sooner (rather than inevitably later!) due to C# compile-time type-checking in your DTO-to-Entity (and Entity-to-DTO) mapping code - that's a benefit right there.
But the main benefit is that it allows you to completely abstract-away your underlying database design - and so, in our example, if you have remote clients that depend on Customer address information being inline then your Customer DTO can still emulate the older design by inlining the first Customer Address into the original Customer DTO when it renders its JSON/XML/Protobuf response to the remote client. That saves time, trouble, effort, money, stress, complaints, firings, unnecessary beatings, grievous bodily harm and a scheduled dental hygienist's appointment.
Anyway, I've modified your posted code to follow the guidance above:
I added [ProducesResponseType] attributes.
I appreciate it is redundant to specify the default response type BookCreateDTO twice (in [ProducesResponseType] as well as ActionResult<BookCreateDTO> - you should be able to remove either one of those without affecting Swagger output.
I added an explicit [FromBody], just to be safe.
If the "book-name is unused" check fails, it returns the model validation message in ASP.NET's stock BadRequest response, which is rendered as an IETF RFC 7807 response, aka ProblemDetails instead of throwing an exception and then hoping that you configured your ASP.NET Core pipeline (in Configure()) to handle it as a ProblemDetails instead of, say, invoking a debugger or using DeveloperExceptionPage.
Note that in the case of a name conflict we want to return HTTP 409 Conflict and not HTTP 400 Bad Request, so the conflictResult.StatusCode = 409; is overwritten.
The final response is generated from a new BookCreateDTO instance via AutoMapper and Ok() instead of serializing your Book entity object.
[ProducesResponseType(typeof(BookCreateDTO), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status409Conflict)]
public async Task< ActionResult<BookCreateDTO> > CreateBook( [FromBody] BookCreateDTO bookCreateDto )
{
// Does a book with the same name exist? If so, then return HTTP 409 Conflict.
if( await _context.Books.AnyAsync(x => x.Name == bookCreateDto.Name) )
{
this.ModelState.Add( nameof(BookCreateDTO.Name), "Book already exists" );
BadRequestObjectResult conflictResult = this.BadRequest( this.ModelState );
// `BadRequestObjectResult` is HTTP 400 by default, change it to HTTP 409:
conflictResult.StatusCode = 409;
return conflictResult;
}
Book addedBook;
{
addedBook = this.mapper.Map<Book>( bookCreateDto );
_ = this.context.Books.Add( book );
_ = await this.context.SaveChangesAsync();
}
BookCreateDTO responseDto = this.mapper.Map<BookCreateDTO >( addedBook );
return this.Ok( responseDto );
}

Related

ASP.NET Web API - method that is called for all requests prior to the routed method?

I'm writing in C# for ASP.NET Web API 2. What I want is a catch-all method that will execute for every single request that comes to my Web API.
If the method returns null, then the original routing should continue, seeking out the correct method. However, if the method returns, say, an HTTPResponseMessage, the server should return that response and not proceed on to normal routing.
The use case would be the ability to handle various scenarios that may impact the entire API. For example: ban a single IP address, block (or whitelist) certain user agents, deal with API call counting (e.g. someone can only make X requests to any API method in Y minutes).
The only way I can imagine to do this right now is to literally include a method call in each and every new method I write for my API. For example,
[HttpGet]
public HttpResponseMessage myNewMethod()
{
// I want to avoid having to do this in every single method.
var check = methodThatEitherReturnsResponseOrNull(Request);
if (check != null) return (HttpResponseMessage)check;
// The method returned null so we go ahead with normal processing.
...
}
Is there some way to accomplish this in routing?
This is what Action Filters are for. These are Attributes that you can place either globally, at the class (Controller), or at the method (Action) levels. These attributes can do preprocessing where you execute some code before your action executes or post processing where you execute code after the action executes.
When using pre processing you have the option to return a result to the caller and not have your method (action) be fired at all. This is good for model validation, authorization checks, etc.
To register a filter globally edit the WebApiConfig.cs file.
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Filters.Add(new YourFilterAttribute()); // add record
// rest of code
}
}
To create a custom attribute inherit from System.Web.Http.Filters.ActionFilterAttribute or you can implement interface System.Web.Http.Filters.IActionFilter or you can implement IAuthorizationFilter/AuthorizationFilterAttribute if you specifically want to allow/deny a request.
It also sounds like you want to create multiple attributes, one for each role like IP filtering or count calling etc. That way it would be more modular instead of one enormous authorization filter.
There are many tutorials out there like this one (chosen at random in my Google search results). I am not going to post code because you did not do so either so I would just be guessing as to what you wanted to do.

BreezeJS modified route not working

My application has two databases with exactly the same schema. Basically, I need to change the DbContext based on what data I'm accessing. Two countries are in one Db and 4 countries in the other. I want the client to decide which context is being used. I tried changing my BreezeWebApiConfig file so that the route looks like this:
GlobalConfiguration.Configuration.Routes.MapHttpRoute(
name: "BreezeApi",
routeTemplate: "breeze/{dbName}/{controller}/{action}/{id}",
defaults: new {id=RouteParameter.Optional,dbName="db1"}
);
I added the string to the controller actions:
[HttpGet]
public string Metadata(string dbName="")
{
return _contextProvider.Metadata();
}
And changed the entityManager service Name.
Now when the client spins up, it accesses the corrent metadata action and I get a message:
Error: Metadata query failed for: /breeze/clienthistory/kenya/Metadata. Unable to either parse or import metadata: Type .... already exists in this MetadataStore
When I go to the metadata url from the browser, I get the correct metadata (exactly the same as when I remove the {dbName} segment from the route). If I remove the {dbName} segment from the route I get no error and everything works fine
(I have not started implementing the multiple contexts yet -- I am just trying to make the additional segment work).
Thanks.
I think the problem is that your Breeze client is issuing two separate requests for the same metadata, once under each of the two "serviceNames". Breeze tries to blend them both into the same EntityManager.metadataStore ... and can't because that would mean duplication of EntityType names.
One approach that should work is to begin your application by fetching the metadata immediately upon app start and then adding all the associated "DataServiceNames" to the MetadataStore.
Try something along these lines (pseudo-code):
var manager;
var store = new breeze.MetadataStore();
return store.fetchMetadata(serviceName1)
.then(gotMetadata)
.catch(handleFail);
function gotMetadata() {
// register the existing metadata with each of the other service names
store.addDataService(new breeze.DataService(serviceName2));
... more services as needed ...
manager = new breeze.EntityManager({
dataService: store.getDataService(serviceName1), // service to start
metadataStore: store
});
return true; // return something
}
Alternative
Other approaches to consider don't involve 'db' placeholder in the base URL nor any toying with the Web API routes. Let's assume you stay vanilla in that respect with your basic service name
var serviceName = '/breeze/clienthistory/';
..
For example, you could add an optional parameter to your routes (let's call it db) as needed via a withParameters clause.
Here is a query:
return new breeze.EntityQuery.from('Clients')
.where(...)
.withParameters({db: database1}); // database1 == 'kenya'
.using(manager).execute()
.then(success).catch(failed);
which produces a URL like:
/breeze/clienthistory/Clients/?$filter=...&db=kenya
It makes an implicit first-time-only metadata request that resolves to:
/breeze/clienthistory/Metadata
Your server-side Web API query methods can expect db as an optional parameter:
[HttpGet]
public string Metadata(string db="")
{
... do what is right ...
}
Saves?
I assume that you also want to identify the target database when you save. There are lots of ways you can include that in the save request
in a custom HTTP header via a custom AJAX adapter (you could do this for queries too)
in a query string parameter or hash segment on the saveChanges POST request URL (again via a custom AJAX adapter).
in the tag property of the saveOptions object (easily accessed by the server implementation of SaveChanges)
in the resourceName property of the saveOptions object (see "named save")
You'll want to explore this variety of options on your own to find the best choice for you.

Web API Complex Data in Get

I am using Web APi, as I am new to this, I dont know much about it.
I am trying to implement search, as of now I am starting with only text search, but later there may be huge search criteria. for one text that is easy, as web api works good with
primitive data types. Now I want to create a class of filter, say the pagenumber , the pagesize also all the search criteria, so I created a class. I have created a MVC application which is communicating with the web api, the web api returns Json data, then I de-serialize it to model. I am stuck with the complex object part, also as of now I am using a list to get the data, later that will be replaced by data base. Following is the code.
public IEnumerable<Document> Get(PaggingDetails request) //public async Task<IEnumerable<Note>> GetNotes() for Async (DB)
{
return _repository.GetAll(pagedetails.PageNumber, pagedetails.PageSize, pagedetails.PageFilter);
//return await db.Notes.ToListAsync<Note>(); for async
}
public string GetPage(int pagenumber,int pagesize,string pagefilter)
{
try
{
PaggingDetails PageDetails = new PaggingDetails();
PageDetails.PageFilter = pagefilter;
PageDetails.PageSize = pagesize;
PageDetails.PageNumber = pagenumber;
return new System.Net.WebClient().DownloadString
("http://.../api/Document/?pagedetails=" +
PageDetails);
//new HttpClient().GetStringAsync("http://localhost:18545/api/Emails"); for async
//also pass parameters
}
catch (Exception ex)
{
}
return "";
}
By deafult, you cannot use a class as the type of parameter of a GET Web API action. You need to use individual parameters of single types.
If you want to use a class as parameter nothing stops you to use a POST action, in which you can include the data without any problem.
However you can force a complex parameter of a GET action to be read from the URI by decorating the comples attribute with [FromUri].
You can read this document to better understand Web API parameter binding:
Parameter Binding in ASP.NET Web API
By default, Web API uses the following rules to bind parameters:
If the parameter is a “simple” type, Web API tries to get the value from the URI. Simple types include the .NET primitive types (int, bool, double, and so forth), plus TimeSpan, DateTime, Guid, decimal, and string, plus any type with a type converter that can convert from a string. (More about type converters later.)
For complex types, Web API tries to read the value from the message body, using a media-type formatter.
This is the standard way of working. If you use the [FromUri] attribute, the action selector won't be able to choose between different Get methods that receive different complex types. If you use a route with controller and action segments, you won't have that problem, becaus ethe actions selector will choose by action name, no matter what the aprameters are.
I don't like using the [FromUri] for this reason, and beacuse it's not the natural way to work with the GET action. But you can use it with the necessary precautions.

How do you use optimistic concurrency with WebAPI OData controller

I've got a WebAPI OData controller which is using the Delta to do partial updates of my entity.
In my entity framework model I've got a Version field. This is a rowversion in the SQL Server database and is mapped to a byte array in Entity Framework with its concurrency mode set to Fixed (it's using database first).
I'm using fiddler to send back a partial update using a stale value for the Version field. I load the current record from my context and then I patch my changed fields over the top which changes the values in the Version column without throwing an error and then when I save changes on my context everything is saved without error. Obviously this is expected, the entity which is being saved has not been detacched from the context so how can I implement optimistic concurrency with a Delta.
I'm using the very latest versions of everything (or was just before christmas) so Entity Framework 6.0.1 and OData 5.6.0
public IHttpActionResult Put([FromODataUri]int key, [FromBody]Delta<Job> delta)
{
using (var tran = new TransactionScope())
{
Job j = this._context.Jobs.SingleOrDefault(x => x.JobId == key);
delta.Patch(j);
this._context.SaveChanges();
tran.Complete();
return Ok(j);
}
}
Thanks
I've just come across this too using Entity Framework 6 and Web API 2 OData controllers.
The EF DbContext seems to use the original value of the timestamp obtained when the entity was loaded at the start of the PUT/PATCH methods for the concurrency check when the subsequent update takes place.
Updating the current value of the timestamp to a value different to that in the database before saving changes does not result in a concurrency error.
I've found you can "fix" this behaviour by forcing the original value of the timestamp to be that of the current in the context.
For example, you can do this by overriding SaveChanges on the context, e.g.:
public partial class DataContext
{
public override int SaveChanges()
{
foreach (DbEntityEntry<Job> entry in ChangeTracker.Entries<Job>().Where(u => u.State == EntityState.Modified))
entry.Property("Timestamp").OriginalValue = entry.Property("Timestamp").CurrentValue;
return base.SaveChanges();
}
}
(Assuming the concurrency column is named "Timestamp" and the concurrency mode for this column is set to "Fixed" in the EDMX)
A further improvement to this would be to write and apply a custom interface to all your models requiring this fix and just replace "Job" with the interface in the code above.
Feedback from Rowan in the Entity Framework Team (4th August 2015):
This is by design. In some cases it is perfectly valid to update a
concurrency token, in which case we need the current value to hold the
value it should be set to and the original value to contain the value
we should check against. For example, you could configure
Person.LastName as a concurrency token. This is one of the downsides
of the "query and update" pattern being used in this action.
The logic
you added to set the correct original value is the right approach to
use in this scenario.
When you're posting the data to server, you need to send RowVersion field as well. If you're testing it with fiddler, get the latest RowVersion value from your database and add the value to your Request Body.
Should be something like;
RowVersion: "AAAAAAAAB9E="
If it's a web page, while you're loading the data from the server, again get RowVersion field from server, keep it in a hidden field and send it back to server along with the other changes.
Basically, when you call PATCH method, RowField needs to be in your patch object.
Then update your code like this;
Job j = this._context.Jobs.SingleOrDefault(x => x.JobId == key);
// Concurrency check
if (!j.RowVersion.SequenceEqual(patch.GetEntity().RowVersion))
{
return Conflict();
}
this._context.Entry(entity).State = EntityState.Modified; // Probably you need this line as well?
this._context.SaveChanges();
Simple, the way you always do it with Entity Framework: you add a Timestamp field and put that field's Concurrency Mode to Fixed. That makes sure EF knows this timestamp field is not part of any queries but is used to determine versioning.
See also http://blogs.msdn.com/b/alexj/archive/2009/05/20/tip-19-how-to-use-optimistic-concurrency-in-the-entity-framework.aspx

TempData implementation changes - Reasons for the change

In ASP.NET MVC 2, the lifespan of an entry in the TempDataDictionary was just one HTTP Request.
That translated to setting a value in one request, redirecting, and having access to the same item at the other end of the line. After this the entry would be no longer available, regardless of whether you read the value out of the dictionary at the latter end of the line or not.
Since ASP.NET MVC 3 (I believe), this implementation detail has changed quite significantly.
Entries in the TempDataDictionary are now only removed once they've been read.
MVC 4
public object this[string key]
{
get
{
object obj;
if (!this.TryGetValue(key, out obj))
return (object) null;
this._initialKeys.Remove(key);
return obj;
}
}
and
public bool TryGetValue(string key, out object value)
{
this._initialKeys.Remove(key);
return this._data.TryGetValue(key, out value);
}
MVC 2:
public object this[string key] {
get {
object value;
if (TryGetValue(key, out value)) {
return value;
}
return null;
}
and
public bool TryGetValue(string key, out object value) {
return _data.TryGetValue(key, out value);
}
Since most people seem to put items in the TempData collection in one request and immediately read them back out in the immediate next request, the functionality seems roughtly the same.
In scenarios where this is not the case such as wanting to read the TempData entry if redirected to one place, and expecting it to have been removed if requesting other resources and navigating back, this change has quite an impact.
No longer is the entry available for one http request but is available over many HTTP requests, be it only available to one single get on the dictionary.
I'd like to know more about this implimentation change, what were the reasons for the change, was this simply to cater for multiple redirects or are there deeper benefits?
Secondary to that, I'm intrigued to know if there's anything built in that now caters for single HTTP request sharing of data in the same way that TempData used to cater for?
You're correct that TempData keys are only cleared if they’ve been read (or after the user’s session expires) but this has been the case since MVC2, (http://forums.asp.net/post/3692286.aspx)
I'd like to know more about this implimentation change, what were the
reasons for the change, was this simply to cater for multiple
redirects or are there deeper benefits?
This change prevented problems that arose in MVC 1, such as TempData keys being deleted before they were read. So yes, the primary benefit is in avoiding these problems when you have multiple re-directs, or interleaved requests. In addition, the RedirectToRouteResult or RedirectResult methods now automatically call TempData.Keep() to prevent clearing of keys, even after they've been read so keep that in mind as well.
In scenarios where this is not the case such as wanting to read the
TempData entry if redirected to one place, and expecting it to have
been removed if requesting other resources and navigating back, this
change has quite an impact.
You’re correct, if you've been coding under the assumption that the TempData keys are cleared automatically you could run into unexpected problems. You can call TempData.Clear() to manually remove all keys from the TempDataDictionary, or TempData.Remove(key) to remove a specific key. You can also use TempData.Peek() to read the value of a TempData key without flagging it for removal from the TempDataDictionary.
Secondary to that, I'm intrigued to know if there's anything built in
that now caters for single HTTP request sharing of data in the same
way that TempData used to cater for?
I'm not aware of any new objects or functions that replicate the original implementation of TempData. Essentially we still use TempData but have to be mindful that the data persists until read and clear the dictionary manually if needed.

Resources