Im using VS2012, ASP MVC4.
I want validate the new registered user email using this on my model:
[DataType(DataType.EmailAddress)]
[Display(Name = "Email")]
[EmailAddress]
public string Email { get; set; }
This works, but I want block some email sites how: 10minutemail, etc.. I want searching a option that allows me config the DataType Email Anotation or extends it..
I thinks this can be more clean that a big regex that validate all.
Thanks a lot
You can create a custom email validation attribute that wraps over EmailAddressAttribute you are using now:
public class CustomEmailValidationAttribute : ValidationAttribute
{
private string[] blockedProviders = new[]
{
"10minutemail.com",
"some-temporary-email.net"
};
protected override ValidationResult IsValid(object value,
ValidationContext validationContext)
{
var emailValidationAttribute = new EmailAddressAttribute();
if (!emailValidationAttribute.IsValid(value))
return new ValidationResult("Invalid email");
bool isBlocked = blockedProviders.Any(pr => ((string)value)
.EndsWith(pr, StringComparison.InvariantCultureIgnoreCase));
if (isBlocked)
return new ValidationResult("Email provider is not allowed");
return ValidationResult.Success;
}
}
Then you can mark email fields with [CustomEmailValidation] instead of [EmailAddress].
Related
I'm using Glass V4. I have a set up of MVC Web Area Project.
I have installed the Glass Mapper in the Main Project (WebProject).
I'm trying to do the Glass Casting in my Area Project.
public class ContactController : SitecoreController
{
private readonly ISitecoreContext _context;
private IGlassHtml _glassHtml;
public ContactController()
: this(new SitecoreContext())
{
}
public ContactController(ISitecoreContext context)
{
_context = context;
_glassHtml = new GlassHtml(context);
}
// GET: Contact
public ActionResult ContactUs()
{
var db = Sitecore.Context.Database;
var datasource = db.GetItem(RenderingContext.Current.Rendering.DataSource);
var ViewModel = new Models.ContactUs();
ViewModel.Headerstring = datasource.Fields["Headerstring"].Value;
ViewModel.Substring = datasource.Fields["Substring"].Value;
ViewModel.Description = ((MultilistField)datasource.Fields["Description"]).GetItems().Select(s => s.Fields["Line"].Value).ToList<string>();
return View(ViewModel);
}
public ActionResult ContactUsGlass()
{
var model = _context.GetCurrentItem<ContactUsGlassModel>();
return View(model);
}
}
I'm able to get the value with the First Action Method but not with the second.
Model:
public class ContactUs
{
public string Headerstring { get; set; }
public string Substring { get; set; }
public List<string> Description { get; set; }
}
Glass Model:
public class ContactUsGlassModel
{
public virtual string Headerstring { get; set; }
public virtual string Substring { get; set; }
}
I understand I don't need to register my Namespace in Glass V4.
You should not use _context.GetCurrentItem method. Use _context.GetItem instead:
public ActionResult ContactUsGlass()
{
var model = context.GetItem<ContactUsGlassModel>(RenderingContext.Current.Rendering.DataSource);
return View(model);
}
You don't want to get model from your Sitecore.Context.Item (which is used in GetCurrentItem method. You want to get your model from the DataSource of the current rendering.
What #Marek has answered is the right way of pulling the rendering item into model. GetCurrentItem by default gives the page item being served by Sitecore. If the fields that your model needs are fields of your page item then GetCurrentItem can also fill your model. If Datasource nesting is enabled, then if the datasource is not set on the rendering, Sitecore returns the page item again.
You can inherit from GlassController and then use GetLayoutItem() to get the datasorced item. If it's null then you need to publish the template in sitecore and make sure you mappings are correct if you are not using TDS :)
In my class, I have a property for a file attachment like so...
public class Certificate {
[Required]
// TODO: Wow looks like there's a problem with using regex in MVC 4, this does not work!
[RegularExpression(#"^.*\.(xlsx|xls|XLSX|XLS)$", ErrorMessage = "Only Excel files (*.xls, *.xlsx) files are accepted")]
public string AttachmentTrace { get; set; }
}
I don't see anything wrong with my regex, but I always get ModelState.IsValid false. This seems pretty trivial and simple regex, am I missing something? Do I need to write my own custom validation?
I'm populating AttachmentTrace via a regular input of type file:
<div class="editor-label">
#Html.LabelFor(model => model.AttachmentTrace)
</div>
<div class="editor-field">
#Html.TextBoxFor(model => model.AttachmentTrace, new { type = "file" })
#Html.ValidationMessageFor(model => model.AttachmentTrace)
</div>
The action method is just a regular action:
public ActionResult Create(Certificate certificate, HttpPostedFileBase attachmentTrace, HttpPostedFileBase attachmentEmail)
{
if (ModelState.IsValid)
{
// code ...
}
return View(certificate);
}
Ok, here's the solution I found. I'm sure there are other solutions out there. First a little background, because my application uses EF code-first migration, specifying a HttpPostedFileBase property type in my model, produces this error when adding migration:
One or more validation errors were detected during model generation:
System.Data.Entity.Edm.EdmEntityType: : EntityType
'HttpPostedFileBase' has no key defined. Define the key for this
EntityType. \tSystem.Data.Entity.Edm.EdmEntitySet: EntityType:
EntitySet 'HttpPostedFileBases' is based on type 'HttpPostedFileBase'
that has no keys defined.
So I really had to stick with using a string type for the AttachmentTrace property.
The solution is to employ a ViewModel class like this:
public class CertificateViewModel {
// .. other properties
[Required]
[FileTypes("xls,xlsx")]
public HttpPostedFileBase AttachmentTrace { get; set; }
}
Then create a FileTypesAttribute like so, I borrowed this code from this excellent post.
public class FileTypesAttribute : ValidationAttribute {
private readonly List<string> _types;
public FileTypesAttribute(string types) {
_types = types.Split(',').ToList();
}
public override bool IsValid(object value) {
if (value == null) return true;
var postedFile = value as HttpPostedFileBase;
var fileExt = System.IO.Path.GetExtension(postedFile.FileName).Substring(1);
return _types.Contains(fileExt, StringComparer.OrdinalIgnoreCase);
}
public override string FormatErrorMessage(string name) {
return string.Format("Invalid file type. Only {0} are supported.", String.Join(", ", _types));
}
}
In the controller Action, I needed to make a change to use the ViewModel instead, then map it back to my Entity using AutoMapper (which is excellent by the way):
public ActionResult Create(CertificateViewModel certificate, HttpPostedFileBase attachmentTrace, HttpPostedFileBase attachmentEmail) {
if (ModelState.IsValid) {
// Let's use AutoMapper to map the ViewModel back to our Certificate Entity
// We also need to create a converter for type HttpPostedFileBase -> string
Mapper.CreateMap<HttpPostedFileBase, string>().ConvertUsing(new HttpPostedFileBaseTypeConverter());
Mapper.CreateMap<CreateCertificateViewModel, Certificate>();
Certificate myCert = Mapper.Map<CreateCertificateViewModel, Certificate>(certificate);
// other code ...
}
return View(myCert);
}
For the AutoMapper, I created my own TypeConverter for the HttpPostedFileBase as follows:
public class HttpPostedFileBaseTypeConverter : ITypeConverter<HttpPostedFileBase, string> {
public string Convert(ResolutionContext context) {
var fileBase = context.SourceValue as HttpPostedFileBase;
if (fileBase != null) {
return fileBase.FileName;
}
return null;
}
}
That's it. Hope this helps out others who may have this same issue.
I am currently experimenting with validation attributes,
and now I am trying to validate my ViewModel which contains an EmailAddress with a custom validation attribute.
public class UserLoginModel
{
[Required]
[EmailAddress]
public string email { get; set; }
[Required]
public string password { get; set; }
public bool rememberMe { get; set; }
}
I have made a unit-test where I give a false email address and try to validate my viewmodel.
[TestMethod]
public void TestingInvalidEmailAddress()
{
UserLoginModel model = new UserLoginModel();
model = GetAValidLoginModel(); //Get a default-model where all parameters are correct
model.email = "thisisnotavalidemail.com";
ValidationContext context = new ValidationContext(model, null, null);
var results = new List<ValidationResult>();
bool validModel= Validator.TryValidateObject(model, context, results);
//This is always true
Assert.IsFalse(validModel);
}
The result of this test is always False.
So I checked my attribute, because I thought I might have made a mistake:
[TestMethod]
public void Email()
{
string email;
var attr = new EmailAddressAttribute();
email = "myemail#domain.com";
Assert.IsTrue(attr.IsValid(email));
email = "thisisnotavalidemail.com";
Assert.IsFalse(attr.IsValid(email)); //If this fails, the test is successfull
}
And that did pass the test, using the exact same email address.
And when I test it in my browser, it also validates correctly.
So why does it not tell me that my email address is invalid in the first test-method?
I found my solution in over here.
Apparently I am just missing an extra parameter.
bool validModel= Validator.TryValidateObject(model, context, results, **true**);
to extend my validation I have created my own model binder based on following article:
http://www.howmvcworks.net/OnModelsAndViewModels/TheBeautyThatIsTheModelBinder
In my application I extend my Person entity like this:
[MetadataType(typeof (PersonMetaData))]
public partial class Person { }
public class PersonMetaData {
[CustomRegularExpression(#"(\w|.)+#(\w|.)+", ErrorMessage = "Email is invalid")]
public string Name;
}
My global.asax looks like this:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
//Change default modelbinding
ModelBinders.Binders.DefaultBinder = new CustomModelBinder();
}
When I call the create event for my PersonController and the provided email is invalid, the ModelState.Valid field is false.
Now I like to create a unit test for the create method:
[TestInitialize()]
public void MyTestInitialize()
{
RegisterRoutes(RouteTable.Routes);
//Change default modelbinding
ModelBinders.Binders.DefaultBinder = new CustomModelBinder();
}
/// <summary>
///A test for Create
///</summary>
// TODO: Ensure that the UrlToTest attribute specifies a URL to an ASP.NET page (for example,
// http://.../Default.aspx). This is necessary for the unit test to be executed on the web server,
// whether you are testing a page, web service, or a WCF service.
[TestMethod()]
public void CreateTest()
{
PersonController controller = new PersonController();
Person Person = new Person();
Person.Email = "wrognmail.de
var validationContext = new ValidationContext(Person, null, null);
var validationResults = new List<ValidationResult>();
Validator.TryValidateObject(Person, validationContext, validationResults, true);
foreach (var validationResult in validationResults)
{
controller.ModelState.AddModelError(validationResult.MemberNames.First(), validationResult.ErrorMessage);
}
ActionResult actual;
actual = controller.Create(Person);
// Make sure that our validation found the error!
Assert.IsTrue(controller.ViewData.ModelState.Count == 1, "err.");
}
When I debug the code the ModelState.Valid attribute is telling me that there is no error. I think that the registration of the DefaultBinder was not sucessfull.
How can I register my DefaultBinder in my unit test?
Thank you!
Have a look at this question and Darin's answer. It`s the way to test model binder, might help you.
I was wondering if anyone had any pointers for parsing json data consumed from a URL in Asp.Net. I've found plenty of docs about Model Binding json datatypes but this is coming from a URL and I cant seem to find an example for that. The closest thing I've found is datacontractjsonserializer but again, I cant seem to find an example of that in context with a URL outputting the json data. Any help is appreciated.
You could use the JavaScriptSerializer class. You start by defining a model class which will hold the data. So let's suppose that the remote URL returns the following JSON:
{ name: 'John', addresses: [ { city: 'Paris' }, { city: 'London' } ] }
which could be represented by this model:
public class Person
{
public string Name { get; set; }
public Address[] Addresses { get; set; }
}
public class Address
{
public string City { get; set; }
}
And then deserialize the received JSON back to the model:
var serializer = new JavaScriptSerializer();
// TODO: Fetch the JSON from a remote URL
var json = "{name: 'foo', addresses: [{city: 'Paris'}, {city: 'London'}]}";
var person = serializer.Deserialize<Person>(json);
UPDATE:
In order to fetch the JSON from remote url you could use WebClient:
using (var client = new WebClient())
{
string json = client.DownloadString("http://someurl.com");
}
Here is what I have so far. A product of all answers that I get here in stack.
The idea is to get the json value from external web service and publish it in my controller as a json values and I dont have to create model for it. Hope this helps.
public class ApiJson: Controller
{
public JsonResult getUser()
{
WebClient client = WebClient();
NameValueCollection data = new NameValueCollection();
data.Add("param1", "value1");
byte[] result = client.UploadValues("http://localhost:9000/", data);
String json = Encoding.ASCII.GetString(result);
JavaScriptSerializer serializer = new JavaScriptSerializer();
dynamic item = serializer.Deserialize<object>(json);
return Json(item, JsonRequestBehavior.AllowGet);
}
}