Generic Remote Validations in MVC 5 - c#

I am developing an MVC 5 app using EF 6 database first approach. I have a certain validation which is required for fields in many of my models. I am using remote validation for validating them. Since it was being used in a lot of models so I am trying to go for a generic method.
For that matter I made an Interface named IEntity which includes all properties being used in my models. Then I did the following for my Validation method:
[HttpPost]
public JsonResult UniqueCheck<T>(T code) where T : class, IEntity
{
MyEntities db = new MyEntities();
if (db.Set<T>().Any(x=>x.S1 == code.S1))
{
return Json("Already Exists!");
}
else
{
return Json(true);
}
}
And following is how I am calling the validation on properties in models:
[Remote("UniqueCheck", "Rules", HttpMethod = "POST")]
public string S1 { get; set; }
But the problem is that the validation is not working and when I checked in the browser console I got that the validation is actually going into the method but there was a 500(Internal Server Error) returned.
I know that the problem is with T written with method name because when I removed the generics and hardcoded my model name, it works fine.
I only want to use MVC's remote validation and I would be very happy to get this generic method working because otherwise it would be a copy/paste on a lot of locations.

Related

Validating data in the service layer against DTOs, Entity Models, or something else?

I'm working on an ASP.NET MVC project. In the project I have a service layer that accepts DTOs for CRUD operations. When I need to validate business logic, should the validator accept DTOs, Entity Models, or something else entirely?
For example:
public class ProductService: IProductService
{
public ValidationResult CreateProduct(ProductDTO productDto)
{
//call productValidator.Validate(productDto) on the DTO here?
Product productEntityModel = mapper.Map<Product>(productDto);
//or, call productValidator.Validate(productEntityModel) on the Entity model here?
if(validationResult.Valid)
{
_dbContext.Products.Add(productEntityModel);
_dbContext.SaveChanges();
}
return validationResult
}
}
Some thoughts:
I've seen online some talk of creating a POCO which can have validation logic (rather than using a validation service) and even other business logic inside of it. This makes sense, but it is yet one more "representaion" of a product that has to be managed and maintained.
Validating against the DTO maybe seems a little more reasonable since that is that the caller is sending to the service?
Thanks for the help!!
When I need to validate business logic, should the validator accept
DTOs, Entity Models, or something else entirely?
Normally, we perform validation in ViewModel class using DataAnnotations, so that we can return user friendly ModelError. For example,
public class LoginViewModel
{
[Display(Name = "Username")]
[Required(ErrorMessage = "Please enter your username.")]
public string UserName { get; set; }
}
public async Task<ActionResult> Login(LoginModel model, string returnUrl)
{
if (ModelState.IsValid)
{
...
ModelState.AddModelError("", "User is not authorized!");
}
...
}
Although you can validate some business logic inside ProductService, you cannot return MVC ModelError, since Service/Repository Layer should not depends on ASP.NET MVC (or any UI components).
Most of the error inside Service/Repository Layer are unexpected error instead of user error. We norammly log those error in NLog or Log4Net, and redirect user to custom error page.

MVC Project and MVC project with API

I have recently started working on MVC application. However my first plan was to create two separate projects in the same solution. One asp.net MVC web application and second is asp.net WebAPI. So that my Web Application will talk to Web API which in return will send JSON response to application which will be converted to View Model for View.
Workflow Diagram :
As i studied more i got to know that API controller and controller both merged into a single controller class in MVC 5. so here is my question how can i achieve the above workflow in MVC 5.
MVC 5 Workflow Diagram
So here comes the problem for me in MVC 5 or i am unable to understand it completely E.g :
UserModel
public class UserModel
{
Public int UserId {get;set;}
Public string Username {get;set;}
}
UserController
[HttpGet()]
public IActionResult GetUser(int id)
{
// do some work
return View(userObject);
}
View
#model UserModel
<h1>#Model.Username</h1>
but when i call the above method from mobile it will give me the rendered html which is not useful for me so do i need to create another method in the same controller in which will return data in JSON.
[HttpGet()]
public IActionResult ApiGetUser(int id)
{
// do some work
return JSONResponse.. ;
}
Modifying method :
[HttpGet()]
public IActionResult GetUser(int id)
{
// calling api get user method
ApiGetUser(int id); // return json
// do some work to convert json into ModelObject
return View(userObject);
}
And if any one mobile app needs data it can call m APIGetUser Method but in this scenario for me its tedious and no of extra methods will be added in the same class. So my basic question is my understanding towards the flow is wrong or am i missing somethings because if below mentioned workflow is right than i would prefer the first one as its separate WebAPI project and easy to maintain ?
In my opinion both diagram are architecturally correct.
But you should consider SRP and separation of concern this: if MVC controller + WebApi controller are both an entry point to your application, running the same code and returning it in 2 different way, they are actually doing 2 different things isn'it? One serve the view and the other one the json.
Plus if you have to render a view there are naturally some behaviuour that isn't common with your web api (cache or rendering partial view for example).
If you think the same, you should leave aside that in MVC 5 both MVC+WebApi controller are under the same class and split it for the reason above.
Hope it helps!

How we can create 3 tier architecture in ASP.Net MVC application with EF?

I am creating a new project (web application) in ASP.NET MVC 5 with Entity framework 6. I have worked in 3 tier architecture with ASP.Net web form application but i am confusing to deal with entity framework, models etc.
So, how can i build 3 tier architecture in MVC with EF and it is feasible to use with entity framework ?
Yes you can implement a 3/N tier architecture (or something similar).
ASP.NET MVC has a great collaboration with entity framework. EF even is installed and used for users/roles management (identity) in default ASP.NET MVC template.
A typical ASP.NET MVC application consists of Models, Views and Controllers. Briefly:
Models are POCOs. The model encapsulate data and it's responsible for data validity. For analogy - this is a part of application tier and a part of data tier. The data tier include also EF db context class.
Views are .cshtml files which produce html and can be strongly typed (have model). For analogy - This is the presentation tier.
Controllers are responsible for processing of HTTP requests, retrieving data model and passing the model to the view. For analogy - This is a part of application tier (business logic).
Typically the controller will receive some viewModel, validate it, process it, and return some action result (view, partial view, JSON, file, etc.). In the process part the controller can initialize entity framework context, and gets or save data to database through the EF db context etc.
It's almost always a good idea to "keep the controller as thin as possible", so many ASP.NET MVC solutions use repository/Unit of Work or service pattern.
Example for some typical part of MVC application for creating some entity using services:
Services
// Connect to database through entity framework db context.
public interface IMyService
{
MyDbContext DbContext { get; set; }
IQueryable<Something> GetSomething( ... query params ... );
void CreateSomething(Something model);
// etc.
}
Controller
public MyController
{
private IMyService myService;
public MyController(IMyService myService)
{
this.myService = myService;
}
// Showing create/edit form
[HttpGet]
public ActionResult CreateSomething()
{
// Create Empty view model. new SomeViewModel(); for example.
// Get some nomenclatures for dropdowns etc. through the service (if needed).
// return View(viewModel);
}
// Processing the post request
[HttpPost]
public ActionResult CreateSomething(SomeViewModel viewModel)
{
// Check validity of viewModel (ModelState.IsValid)
// If not valid return View(viewModel) for showing validation errors
// If valid map the viewModel to Model (through AutoMapper or custom mapping)
// Call myService CreateSomething method.
// Redirect to page with details.
}
}
Model
public class Something
{
public int Id { get; set; }
public string Name { get; set; }
// .. more properties (can be decorated with validation attributes)
}
Presentation View Models
// View model for Something class. Including only properties related to the current UI.
public class SomeViewModel
{
public int Id { get; set; }
// .. more properties (can be decorated with validation attributes)
}
View
#model SomeViewModel
<!-- Form -->
#Html.ValidationForModel()
#Html.EditorForModel()
submit button
<!-- /Form -->
Yes you can implement a 3 tier architectur:
Tier (Presentation): Views (this is what the V stands for in MVC
Tier (Logic): Usually the Models and some Helperclasses (this is what the M stand for)
Tier (Data): Whit the help of the Entity Framework you could create a database from your models.
Here's a tutorial on how to use the Entity Framework with ASP.NET MVC.
Here is how you can implement 3-Tier:
Presentation layer include (MVC)
Business Logic Layer will include (C# programming - a dll)
Data access layer will include (C# programming with entity frameworkor- a dll) Business Object Layer will include (Entity Framework models)
Ref: http://www.codeproject.com/Articles/841324/ASP-NET-MVC-Web-App-on-Tier-for-Beginners

asp web api patch implementation

Assume i have this model
public partial class Todo
{
public int id { get; set; }
public string content { get; set; }
public bool done { get; set; }
}
And i send this as json data to my controller as a patch request.
This is mearly the action of toggeling a checkbox.
I think it makes sence that i only want to sent that to my server, and not the entire model.
{ "id":1, "done" : true }
What does my WebApi controller need to look like in order to correctly process this, simple, json patch request ? Should i be using web api for this, or should i use a more rpc styled approach with mvc ?
It seems like a very basic thing to do, but i can't seem to get it right !
I think i might need to use a different parameter in my controller method, but i'm not sure.
Thank you for your time.
You can find PATCH feature in the OData pre-release Nuget package: Microsoft.AspNet.WebApi.OData.
Information how you can use it to create an action for handling PATCH can be found in the Partial Updates (PATCH requests) section of the blog post about OData support in ASP.NET Web API.
Changing the method to PATCH doesn't change Web API behaviour in any way. There is no built in mechanism for doing partial updates. One of the reasons there was no PATCH method for so long is that there is no ubiquitous media type for applying patches to resources.
Secondly, you are asking Web API to do object serialization for you so there just is no such concept of applying a partially updated object. There would be so many conventions to agree on, what does a null value mean, what about an empty value, how do I say "don't update this DateTime". What about related objects, child items? How do you cause a child item to be deleted? Unless the CLR team implements some concept of a type that only contains a subset of members from another type, partial updates and object serialization are not going to go well together.
Aliostad mentions UpdateModel and that is possible when updating from a HTML form because the media type application/x-www-form-urlencoded explicitly allows for an arbitrary set of name value pairs. There is no "object serialization" going on. It is just a match of names from the form being matched to names on the Model object.
For myself, I created a new media type I use to do partial updates that works like a form but is more advanced in that it can handle hierarchial data and it maintains an order to the updates.
ASP.NET Web API seems to be missing UpdateModel, TryUpdateModel, etc.
In ASP.NET MVC, you could use them to achieve the desired effect. I have created a work item in ASP.NET Web Stack which you can vote for and if it gets enough votes, it will be implemented.
I used Microsoft.AspNet.WebApi.OData for my project and I had some problems working with JSON (working with numbers in my case). Also, the OData package has some dependencies which, from my point of view, are too big for a single feature (~7MB with all dependecies).
So I developed a simple library which do what you are asking for: SimplePatch.
How to use
Install the package using:
Install-Package SimplePatch
Then in your controller:
[HttpPatch]
public IHttpActionResult PatchOne(Delta<Todo> todo)
{
if (todo.TryGetPropertyValue(nameof(Todo.id), out int id)) {
// Entity to update (from your datasource)
var todoToPatch = Todos.FirstOrDefault(x => x.id == id);
if (todoToPatch == null) return BadRequest("Todo not found");
todo.Patch(todoToPatch);
// Now todoToPatch is updated with new values
} else {
return BadRequest();
}
return Ok();
}
The library support massive patch too:
[HttpPatch]
public IHttpActionResult PatchMultiple(DeltaCollection<Todo> todos)
{
foreach (var todo in todos)
{
if (todo.TryGetPropertyValue(nameof(Todo.id), out int id))
{
// Entity to update (from your datasource)
var entityToPatch = Todos.FirstOrDefault(x => x.id == Convert.ToInt32(id));
if (entityToPatch == null) return BadRequest("Todo not found (Id = " + id + ")");
person.Patch(entityToPatch);
}
else
{
return BadRequest("Id property not found for a todo");
}
}
return Ok();
}
If you use Entity Framework, you have to add only two lines of code after the call to the Patch method:
entity.Patch(entityToPatch);
dbContext.Entry(entityToPatch).State = EntityState.Modified;
dbContext.SaveChanges();
Furthermore, you can exclude some properties to be updated when the Patch method is called.
Global.asax or Startup.cs
DeltaConfig.Init((cfg) =>
{
cfg.ExcludeProperties<Todo>(x => x.id);
});
This is usefull when you are working with an entity and you don't want to create a model.

Handling different types of users in asp.net mvc

I have 3 different types of users (with different roles) interacting on my web application, they all perform some task - some can be exactly the same e.g. create a quote others can be unique to that specific user e.g. sign off quote.
For more clarity 3 types of users: Client, Supplier, Customer.
Client or Customer can create a quote, however only the Customer can sign off a quote.
How do I ensure my application allows clients to access client speficic controllers and suppliers to access supplier specific controllers or areas. Via Custom Attributes? Do I store the type of user inside a cookie? Is this safe? or Session state? As soon as someone logs onto the system I send back a LoggedOnDTO object on which I store Username, UserID, and type of user....
NOTE: I went away from asp.net build in way of creating users, I have my own custom tables with my custom mechanism for logging into the system. I have a registered Model Bindiner that looks for the prefix and I send in a strongly typed object to each action...
Sample code:
[HttpGet]
public ActionResult AddComment(int quoteid, ClientUserDTO loggedonclientuser)
{
}
[HttpGet]
public ActionResult AddCommentSupplier(int quoteid, Supplier loggedonsuppluser)
{
}
EDIT: This method for some reason seems so much simpler... Is there something wrong with it? Any possible security issues? Threading?
My session controller is:
if (_authService.isValidUser(model))
{
var data = _authService.GetAuthenticationCookieDetails(model);
AuthenticateCookie.AddDetailsToCookie(data);
return Redirect(Url.Action("Index", "Activity"));
}
When I create my cookie... I can simple store "ClientUser", "Supplier" or whatever role they are inside the cookie.
Then I can create an Attribute and read in the cookie data to see if they are a valid user e.g.
public class ClientAuthorizationAttribute : AuthorizeAttribute
{
public bool AlwaysAllowLocalRequests = false;
protected override bool AuthorizeCore(System.Web.HttpContextBase httpContext)
{
if (AlwaysAllowLocalRequests && httpContext.Request.IsLocal)
{
bool authorized = false;
var result = UserDetails.GetTypeFromTicket(httpContext.User.Identity as FormsIdentity);
if (result.Equals("client", StringComparison.OrdinalIgnoreCase))
{
authorized = true;
}
//throw no access exception?
return authorized;
}
return base.AuthorizeCore(httpContext);
}
}
Register the attribute under my base controller and I have a simple working solution???
Write a custom MembershipProvider and a Custom RoleProvider then you can decorate your controler class or specific methods with the attribute
<Authorize(Roles:="ROLENAME")>
You can learn how to make that your asp mvc use the custom membershiprovider in this question It's really easy.
Edited:
The way you did it looks right, but I think you take the long way. Implementing your own MembershipProvider and your own Roleprovider will take you no more than 20 minutes... and you will have the benefits of being working with a well tested and documented system and still having the benefits of use your own database tables for the login. In a simple login system, you only have to write two functions in the roleprovider (GetRolesForUser and IsUserInRole) and only one function in the membershipprovider (ValidateUser) and you will get your system working.
If you want, I can put somewhere (maybe pastebin) a well commented versiĆ³n of a membershipProvider as well of a roleprovider that i'm using in a simple app (they're made in vb.net but i'm sure it will not be a problem)
You can also write generic code in the base controller instead of decorating each action with Authorize attribute. Please refer below url.
Good practice to do common authorization in a custom controller factory?
custom-controller-factory/5361846#5361846

Categories