How to remote validation with Asp.Net MVC 2 - asp.net-mvc-2

I Create this class.
public class UniqueFileNumber : ValidationAttribute
{
private string _LocationFile;
public override string FormatErrorMessage(string str)
{
return ViewRes.ValidationString.Loc_FileNumberExist;
}
public override bool IsValid(object value)
{
DBEntities _db = EntityFactory.GetEntity();
string strName = Convert.ToString(value);
return !_db.Locations.Any(p => p.LocationFile == strName);
}
}
and add this attribute to my entity Like that.
[UniqueFileNumber]
public object FileNumber{ get; set; }
The validation work only on the PostBack (Refresh).
It would be fine if it's work on client side too. In my client side , I add that line
<% Html.EnableClientValidation(); %>
What's the problem here.
thanks.

You have to give it the javascript fonction to use for validation...
check out this post from Phil Haacked ASP.NET MVC 2 Custom Validation
A better example for what you have to do since you still need to go on the server, check
this post from Brad Wilson Remote Validation with ASP.NET MVC 2

One more Remote Validation ASP.NET MVC 2 based on Brad Wilson idea, but used jQuery ajax calls.

Related

EF Code First validating and updating objects

I am working on an N-tier application consisting of a UI layer (MVC), a Business Layer, a Domain layer (for the models) and a DAL for repositories and the EF DbContext.
I'm a bit confused about the inner workings of Entity Framework when updating the properties of an existing object and I'm looking for a good way to validate an object before updating its values in the database.
I have the following model:
public class BlogPost
{
public int BlogPostId { get; set; }
[Required]
public String Title { get; set; }
[Required]
public String Description { get; set; }
[Required]
public DateTime DateTime { get; set; }
public byte[] Image { get; set; }
}
I have the following methods in my manager in BL:
public BlogPost AddBlogPost(string title, string description, byte[] image = null)
{
BlogPost blogPost = new BlogPost()
{
Title = title,
Description = description,
DateTime = DateTime.Now
};
Validate(blogPost);
moduleRepository.CreateBlogPost(blogPost);
return blogPost;
}
public BlogPost ChangeBlogPost(BlogPost blogPost)
{
moduleRepository.UpdateBlogPost(blogPost);
return blogPost;
}
And I have the following methods in my DAL:
public BlogPost CreateBlogPost(BlogPost b)
{
b = context.BlogPosts.Add(b);
context.SaveChanges();
return b;
}
public BlogPost UpdateBlogPost(BlogPost b)
{
context.Entry(b).State = EntityState.Modified;
context.SaveChanges();
return b;
}
My question now is: what's a good way to check that the model is valid before actually trying to change its values in the database?
I was thinking something like this:
public BlogPost ChangeBlogPost(BlogPost blogPost)
{
// STEP 1: put the updated data in a new object
BlogPost updatedBlogPost = new BlogPost()
{
Title = blogPost.Title,
Description = blogPost.Description,
Image = blogPost.Image,
DateTime = blogPost.DateTime
};
// STEP 2: check if the model is valid
this.Validate(updatedBlogPost);
// STEP 3: read the existing blog post with that ID and change the properties
BlogPost b = moduleRepository.ReadBlogPost(blogPost.BlogPostId);
b.Title = blogPost.Title;
b.Description = blogPost.Description;
b.Image = blogPost.Image;
b.DateTime = blogPost.DateTime;
moduleRepository.UpdateBlogPost(blogPost);
return blogPost;
}
EDIT: I figured it's maybe better to just accept primitive types as parameter in the above method instead of the object.
I have a feeling that's too much work for a simple update, but I couldn't find anything else on the internet.
It's probably also worth noting that I'm using a singleton for the DbContext so I have to make sure Entity Framework doesn't change the values in the database before checking that those values are valid (since another call to the context by another class can cause SaveChanges()).
I know singleton on a DbContext is bad practice, but I saw no other option to avoid countless exceptions when working with multiple repositories and entities being tracked by multiple context instances.
PS: I also read about change tracking in Entity Framework but I'm not 100% sure how this will affect what I'm trying to do.
All suggestions and explanations are welcome.
Thanks in advance.
You would check ModelState.IsValid. There are a lot of validation mechanisms built into MVC that you can take advantage of. Built in attributes such as [Required] that you reference above, custom validators, making your business class implement IValidatableObject, overriding EF SaveChanges() to name a few. This article is a good start: https://msdn.microsoft.com/en-us/data/gg193959.aspx
Ok so I kinda answered my own question while doing some research and testing with some dummy data. I thought that when a property changed in MVC as a result of an Edit view, EF also tracked it and changed it in the database.
I figured out that's not how model binding works and realized after some fooling around that model binding actually creates a new object (instead of editing the properties of a dynamic proxy).
I guess I can now just validate the model and then just update the one with the same primary key in the database.

Using EF and WebAPI, how can I return a ViewModel AND support IQueryable/OData? [duplicate]

This question already has answers here:
Web API Queryable - how to apply AutoMapper?
(3 answers)
Closed 9 years ago.
I've got an ASP.NET WebAPI project. I've recently created EntityFramework entities for all my data tables. But I don't want to expose my data layer & schema to my users. How can I map my entities to a ViewModel (automapper?) and provide IQueryable return type so that my API supports OData?
OData supports query composition and SQL-like parameters. I guess I'd need to provide some kind of 2-way translation for the query-composition part? Does that mean a custom LINQ provider? I hope it's easier than that.
Or should I give up on IQueryable/OData?
I found the answer here: Web API Queryable - how to apply AutoMapper?
Instead of using [Queryable] you can use a parameter of type ODataQueryOptions<T> to apply OData operations against any type or LINQ query you wish. Here's a great example that doesn't even need to use AutoMapper:
public virtual IQueryable<PersonDto> Get(ODataQueryOptions<Person> odataQuery){
odataQuery.Validate(new ODataValidationSettings(){
AllowedFunctions = AllowedFunctions.AllMathFunctions
});
var people = odataQuery.ApplyTo(uow.Person().GetAll());
return ConvertToDtos(people);
}
Here's the Microsoft page explaining the specifics of this usage. (about half way down)
I was able to successfully test this using a ViewModel class.
public class InvoiceViewModel
{
public int InvoiceID { get; set; }
public string InvoiceNumber { get; set; }
}
in the Get, select from your entity into your viewmodel:
public override IQueryable<InvoiceViewModel> Get()
{
var ctx = new CreditPointEntities();
return ctx.Invoices.Select(i => new InvoiceViewModel
{
InvoiceID = i.InvoiceID,
InvoiceNumber = i.InvoiceNumber
}).AsQueryable();
}
Make sure you use the viewmodel in your modelbuilder line in webapiconfig.cs
modelBuilder.EntitySet<InvoiceViewModel>("Invoice");
with this, you can use a url like
http://website/odata/Invoice?$filter=InvoiceID eq 1
I confirmed through sql profiler that the filter was being passed through to SQL.
if you are using Automapper, you could use projections in it. Example:
public class ProductsController : EntitySetController<Product, int>
{
private DbProductsContext _db = new DbProductsContext();
public override IQueryable<ProductDto> Get()
{
return _db.Products.Project().To<ProductDto>();
}
...

Cross-table validation in ASP .NET MVC

I'm peforming validation using DataAnnotations and Validation Attributes. I'm using ADO NET Entity Model, Domain Services, RIA Services, Silverlight and my projet has a server side that's in ASP .NET.
I want to perform cross-table validation, how can I access the Entity tables from the CustomValidation method.
Let explain with an example.
Suppose I want to avoid two equally named Companies in my data.
(I'm editing the question because I don't know how to response to added comments.
IT'S NOT WHAT I NEED ACTUALLY, I JUST WANT TO ACCESS DATA FROM THE CUSTOM VALIDATION METHOD THAT IS LOCATED IN THE SERVER SIDE OF MY APPLICATION.)
I decorate:
[CustomValidation(typeof(CustomValidatorType), "CompanyNameValidation")]
public string CustomerName { get; set; }
Then my CustomValidatorType would be:
public static class CustomValidatorType {
public static ValidationResult CompanyNameValidation(string companyName,
ValidationContext validationContext) {
// How can I see if companyName is already present in Customers entity table?
if (*Company name already exists*) {
// How can I access the Customer Entity Table to check the Company Name existence?
return new ValidationResult("Comapny already exists.", new[] { "CustomerName" });
}
else
return ValidationResult.Success;
}
}
Thank you in advance
My best regards
Rafael

Does renderaction calls its corresponding httpPost Action on submit

I'm a little new to asp.net mvc and I have a question (very basic). I have hacked around but I am not totally sure about this and I could'nt find anything particularly helpful.
Assume that I have 2 controllers A and B and 2 views FullView and PartView
public class AController:...
{
//Renders FullView
public ActionResult Create
{
....
}
[HttpPost]
public ActionResult Create
{
....
}
}
public class BController:...
{
//Renders an Arbitrary partial View (PartView)
public ActionResult Create
{
....
}
//Saves the data of the partial View
[HttpPost]
public ActionResult Create
{
....
}
}
the 1st view (FullView) has the code
<%Html.RenderAction("Create", "B"); %>
my question is on submit will BController's action ([HttpPost] Create) run?
Thank you
That depends on what action you specify in your <form /> tag. This doesn't have anything to do with asp.net mvc. If you use Html.BeginForm() without parameters it will post to the current url (not the create action on BController).
Well 1st thing you could do is toggle some breakpoints in your actions and hit f5.
Second - what action is called purely depends on what url you hit with what http method.
But for your case, when you post form A and controller A processes post you might get into validation problems and that's when you return View() on a post action and that's why form B is rendered via its post method.

ASP.NET MVC2: Getting textbox data from a view to a controller

I'm having difficulty getting data from a textbox into a Controller. I've read about a few ways to accomplish this in Sanderson's book, Pro ASP.NET MVC Framework, but haven't had any success.
Also, I've ran across a few similiar questions online, but haven't had any success there either. Seems like I'm missing something rather fundamental.
Currently, I'm trying to use the action method parameters approach. Can someone point out where I'm going wrong or provide a simple example? Thanks in advance!
Using Visual Studio 2008, ASP.NET MVC2 and C#:
What I would like to do is take the data entered in the "Investigator" textbox and use it to filter investigators in the controller. I plan on doing this in the List method (which is already functional), however, I'm using the SearchResults method for debugging.
Here's the textbox code from my view, SearchDetails:
<h2>Search Details</h2>
<% using (Html.BeginForm()) { %>
<fieldset>
<%= Html.ValidationSummary() %>
<h4>Investigator</h4>
<p>
<%=Html.TextBox("Investigator")%>
<%= Html.ActionLink("Search", "SearchResults")%>
</p>
</fieldset>
<% } %>
Here is the code from my controller, InvestigatorsController:
private IInvestigatorsRepository investigatorsRepository;
public InvestigatorsController(IInvestigatorsRepository investigatorsRepository)
{
//IoC:
this.investigatorsRepository = investigatorsRepository;
}
public ActionResult List()
{
return View(investigatorsRepository.Investigators.ToList());
}
public ActionResult SearchDetails()
{
return View();
}
public ActionResult SearchResults(SearchCriteria search)
{
string test = search.Investigator;
return View();
}
I have an Investigator class:
[Table(Name = "INVESTIGATOR")]
public class Investigator
{
[Column(IsPrimaryKey = true, IsDbGenerated = false, AutoSync=AutoSync.OnInsert)]
public string INVESTID { get; set; }
[Column] public string INVEST_FNAME { get; set; }
[Column] public string INVEST_MNAME { get; set; }
[Column] public string INVEST_LNAME { get; set; }
}
and created a SearchCriteria class to see if I could get MVC to push the search criteria data to it and grab it in the controller:
public class SearchCriteria
{
public string Investigator { get; set; }
}
}
I'm not sure if project layout has anything to do with this either, but I'm using the 3 project approach suggested by Sanderson: DomainModel, Tests, and WebUI. The Investigator and SearcCriteria classes are in the DomainModel project and the other items mentioned here are in the WebUI project.
Thanks again for any hints, tips, or simple examples!
Mike
try strongly typing the page to use SearchCriteria to autopost the data like that ex:
public partial class Search: ViewPage<SearchDetails>
This should do it for you (unable to verify this is perfect - typed this from memory):
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult SearchDetails(FormCollection formValues)
{
var txtContents = formValues["Investigator"];
// do stuff with txtContents
return View();
}
1.) Have you looked into ViewModels for your View? In essence that is what your SearchCriteria class is. Make sure you strongly type your view with that model:
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/MyMaster.Master" Inherits="System.Web.Mvc.ViewPage<SearchCritieria>"
Also make sure that you use the HtmlHelper.TextBoxFor method to map this Investigator property to the SearchCritiera model. On Post back your text box value should be there:
'<%=Html.TextBoxFor(model => model.Invesigator)%>'
Good luck!
Also here is a great reference on using ViewModels that I have looked at a lot recently:
http://geekswithblogs.net/michelotti/archive/2009/10/25/asp.net-mvc-view-model-patterns.aspx
Thanks for the tips everyone. For learning purposes, I need to go back and follow the strongly typed route. I'm curious if I would have run into this problem if I would have done that from the beginning.
Until then, the following worked:
Use a submit button
Use this code for the form:
<% using(Html.BeginForm(new { Action = "SearchResults"})) { %> <% } >
Thanks again for you help!
Mike