Custom validation of HttpPostedFileBase - asp.net-mvc

I use MVC5. I've got some issue with file uploading using HttpPostedFileBase. I've got a form where I can can choose a file from my disk and type some information about it(in textbox). When I submit a form the controller action is called. In this action I open file and check if it has some specific data(related with data from textbox). So I do some validation here. I can't do it using JQuery - it's complex. The server side validation is the only option. Finally if validation fails I return model(with file) to the view but after that I've got validation error next to file field but file field is empty. I've read that's hard to return file to the view. I don't want to use ajax to upload file. I want to do it simple. If you got an article that can help, please share it with me.
How can I solve my problem?

I know you mentioned not using AJAX to do file upload, but I think this solution is a very simple one.
Using the following jQuery plugin (https://blueimp.github.io/jQuery-File-Upload/), you can automate that process and if there are any validation issues in your file, then you can return the following model with the error.
string errors = "Errors returned from complex logic";
if (!String.IsNullOrEmpty(errors))
{
// error response
status = new ViewDataUploadFilesResult()
{
name = Path.GetFileName(hpf.FileName),
size = hpf.ContentLength,
error = errors
};
}
Here is the class needed for the response that matches the jQuery file upload documentation: https://github.com/blueimp/jQuery-File-Upload/wiki/Setup
public class ViewDataUploadFilesResult
{
public string name { get; set; }
public int size { get; set; }
public string type { get; set; }
public string url { get; set; }
public string error { get; set; }
}
If I'm understanding correctly, since the file is already on the users computer, you only need to associate the file to the current file they're attempting to upload to returns errors. And to make it so they don't have to reselect the file to upload. I don't see any other reason to need to return the actual file to the user as they already have the file they're uploading.

Related

asp net mvc oracle database fail to retrieve data

I have an Oracle DB set up, and the Database has a bunch of Views.
The view GFL_BUYERS_ID_V has 2 columns of EMPLOYEE_ID and FULL_NAME. The database is already filled before I created the mvc project.
I Add the database successfully and added the a schema modelBuilder.HasDefaultSchema("examplename."); to my context because when I use SQL to retrieve data, I need to do:
SELECT * FROM "examplename".GFL_BUYERS_ID_V
for it to work, I assume that is what it's for. Apologies in advance I am new to .net, mvc and connecting databases.
The following crashes at the .Select and tells me that value cannot be null (I have no clue what is returning a null value, if I inspect values in context->GFL_BUYERS_ID_V when it breaks, in Local there are 0 values, and in Result View it contains all the appropriate one's, I assume this is relevant info but I don't know how to use it):
var model = new EmployeeModel();
using (var context = new OracleContext())
{
model.Buyers = context.GFL_BUYERS_ID_V.Select(s => new EmployeeModel.Buyer
{
BuyerId = s.EMPLOYEE_ID,
FullName = s.FULL_NAME
}).ToList();
}
return View(model);
this is my object:
public class EmployeeModel
{
public int EmployeeModelId { get; set; }
public List<Buyer> Buyers { get; set; }
public class Buyer
{
public int BuyerId { get; set; }
public string FullName { get; set; }
}
}
I know there is a connection to the database and I can query it via VB. I have fiddled enough with the connection string to know it is correct.
Edit: Scratch that I have no clue if my program is able to connect to the Database or not.
Screen shot of the error
If you would like me to provide more information, I will be happy to, really want to make this one work.
Edit 2: This seems like some sick joke clearly it shows a count: how
Is there an inner exception which is causing the ArgumentNullException?
You are definitely thinking along the right path, so I would break it down into manageable pieces:
1) confirm DB connectivity
2) confirm context is valid, which would most likely only be invalid if no DB connectivity
3) confirm GFL_BUYERS_ID_V is showing data
4) then do the projection to a different model
So the problem was in the Database server not the code. For some reason it used an old default schema variable that wasn't used for a long time.

Asp.net core MVC post parameter always null

I am new to MVC core.
I have created a project with MVC core which has a controller. This controller has Get and Post action methods. If i pass data to Get method using query string it works fine, but when i pass complex JSON to post method, then it always shows me null.
Here what i am doing:
Post Request
URL: http://localhost:1001/api/users
Content-Type: application/json
Body:
{
"Name":"UserName",
"Gender":"Gender of the user",
"PhoneNumber":"PhoneNumber of the user"
}
Here is the Post action method
[HttpPost]
[Route("api/users")]
public async Task<IActionResult> Post([FromBody]User newUser)
{
...
}
When post request is called, then newUser always shows me null. And if i remove [FromBody] attribute then i receive newUser object but all of its fields are null.
Please help me and guide me in this issue.
EDITED
Here is my User class
public class User{
public int Id { get; set; }
public string Name { get; set; }
public string Gender { get; set; }
public string PhoneNumber { get; set; }
}
I had done same as described here for json data, but still receives null.
This could be because of how the null values are being handled. Set NullValueHandling to Ignore in AddJsonOptions and see if that works.
public void ConfigureServices(IServiceCollection services)
{
services
.AddMvc()
.AddJsonOptions(jsonOptions=>
{
jsonOptions.SerializerSettings.NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore;
});
}
Note the original method Post([FromBody] User newUser)
For future readers from google, this same issue could arise if the method was Post(User newUser)
Note the lack of [FromBody]. This is a departure from previous versions of MVC where these parameters were generally inferred.
If you're an existing MVC5 developer who finds this page regarding AspNetCore.MVC, make sure to double check that you have [FromBody] decorated where relevant.
I created new ASP.NET Core project, added your functionality, and it works. Please, checkout this project on github.
Also, see screenshot of log with simple communication with this controller from browser console: Console output
Are you on Microsoft.AspNetCore.Mvc 1.0.0?
If you are, try sending this object as your body in a request (camel cased properties):
{
"name":"UserName",
"gender":"Gender of the user",
"phoneNumber":"PhoneNumber of the user"
}

How do I specify multiple parameters in Asp.Net MVC 5 Route attributes?

I'm using the Kendo AutoComplete client javascript widget, which sends server requests such as the following:
https://domainName/Proto2/api/Goal/Lookup?text=ABC&goalId=8b625c56-7b04-4281-936f-b88d7ca27d76&filter%5Blogic%5D=and&filter%5Bfilters%5D%5B0%5D%5Bvalue%5D=&filter%5Bfilters%5D%5B0%5D%5Boperator%5D=contains&filter%5Bfilters%5D%5B0%5D%5Bfield%5D=Description&filter%5Bfilters%5D%5B0%5D%5BignoreCase%5D=true&_=1423833493290
The MVC server side method to receive this is:
[Route("api/Goal/Lookup")]
[HttpGet] // if the action name doesn't start with "Get", then we need to specify this attribute
public ICollection<IAllegroGoalContract> Lookup(Guid goalId, string text = "")
The problem occurs if the client sends an empty value for the text parameter (ex: text=&goalId=8b625c56-7b04-4281-936f-b88d7ca27d76). In this case .net returns the following error.
"System error - unable to process parameters
(goalId,text,text.String) - invalid data detected"
I've tried various Route attribute values:
[Route("api/Goal/Lookup/{goalId:guid},{text?}")]
[Route("api/Goal/Lookup/{text?}")]
Looks like your parameters are used as a filter, so instead of the GoalId and Text parameters to be part of the route, define a class like this:
public class LookupOptions
{
public Guid GoalId { get; set; } // change this to Guid? if the client can send a nullable goalId.
public string Text { get; set; }
}
So your method signature will be :
[Route("api/Goal/Lookup")]
[HttpGet]
public ICollection<IAllegroGoalContract> Lookup([FromUri]LookupOptions options)
{
// Note that [FromUri] will allow the mapping of the querystring into LookupOptions class.
}
Now, you can pass your options from the client as part of the Query string and it will be assigned to the LookupOptions parameter.
Hope this helps.

Sitecore PageEditor randomly shows error with Glass.Mapper

I sometimes receive an error when I open a page in page editor mode on my Sitecore site using Glass.Mapper.
You cannot save a class that does not contain a property that
represents the item ID. Ensure that at least one property has been
marked to contain the Sitecore ID. Type:
Castle.Proxies.IBasicPageProxy
at Glass.Mapper.Sc.Configuration.SitecoreTypeConfiguration.ResolveItem(Object
target, Database database)
at Glass.Mapper.Sc.GlassHtml.MakeEditable[T](Expression'1 field, Expression'1 standardOutput, T model, Object parameters,
Context context, Database database, TextWriter writer)
This appears in the place of the rendering, so it doesn't show up as a standard ASP error.
Restarting IIS solves this, but soon it appears again..
I use interfaces for model definitions, with every single interface inheriting from IBaseType:
[SitecoreType]
public interface IBaseType
{
[SitecoreId]
Guid Id { get; set; }
[SitecoreInfo(SitecoreInfoType.Name)]
string Name { get; set; }
[SitecoreItem]
Item InnerItem { get; set; }
[SitecoreInfo(SitecoreInfoType.Url)]
string Url { get; set; }
[SitecoreInfo(SitecoreInfoType.TemplateId)]
Guid TemplateId { get; set; }
[SitecoreInfo(SitecoreInfoType.FullPath)]
string FullPath { get; set; }
}
I use Sitecore 7.5 rev. 141003 (.NET 4.5, MVC5), and the latest versions of Glass.Mapper related NuGet packages currently:
Castle.Windsor 3.3.0
Castle.Core 3.3.3
Glass.Mapper 3.0.14.26
Glass.Mapper.Sc 3.2.3.46
Glass.Mapper.Sc.CastleWindsor 3.3.0.24
Glass.Mapper.Sc.Mvc-5 3.3.0.43
The issue appears on all machines we tried, but all of them uses Windows 8, IIS 8.5.9600. I tried reverting to the WebActivator method, but it didn't help. Model definitions are in a separate class library project, which references all glass mapper assemblies.
I'm pretty clueless, never run into this error before on other projects. Does anyone have any idea what can cause this, or how I could debug it?
Thank you for your help!
I have put below code in my model and it works
[SitecoreId]
public virtual Guid Id { get; set; }
Glass mapper requires Item to be represented by a ID. If the glass model does not have a property for GUID, you will see this error.
You can fix this by adding the property public virtual GUID Id {get; set;} to your glass model

asp.net mvc validation must be a number custom error

I am new to asp.net and I have a problem. When the users insert in a editor for a decimal field something other than numbers, they get an error "Field name" is not a number. But I don't want them to receive this message I want them to receive another message. I have no problem with this with required and range validators.
Is there any way for me to do this?
I am not refering necessarily to changing the culture just displaying another message.
Thanks.
Hope I understand your, to change RangeValidator ErrorMessage just initialize ErrorMessage parameter:
[Range(0, 100, ErrorMessage = "Some another error message insert here!")]
[RegularExpression("\d", ErrorMessage = "!!!")]
public decimal DecimalField { get; set; }
This is the actual answer:
Create a class CustomClientDataTypeModelValidatorProvider. Copy the code from the MVC sources. Change the method MakeErrorString to output the appropiate message like this:
private static string MakeErrorString(string displayName)
{
return string.Format(
CultureInfo.CurrentCulture,
Core.Resources.Errors.EroareNuENr,
displayName);
}
I couldn't find a way not to copy the code just extend it as it uses this static method.
If anyone knows this please tell me.
Then, in global.asax, I wrote this:
var cdProvider = ModelValidatorProviders.Providers.SingleOrDefault(p => p.GetType().Equals(typeof(ClientDataTypeModelValidatorProvider)));
if(cdProvider != null)
{
ModelValidatorProviders.Providers.Remove(cdProvider);
ModelValidatorProviders.Providers.Add(
new CustomClientDataTypeModelValidatorProvider());
}
so that the flow would actually be routed to my class and not the class in the asp.net MVC dll
I got the idea from here:
Unfortunately this is is not a trivial task. However you can try the following hack...
Better to do this only on essential fields, as this is more code to maintain.
In the controller's action method
if(ModelState.IsValid)
{
// code
}
else
{
if (ModelState["YourField"].Errors.Count > 0)
{
ModelState["YourField"].Errors.Clear();
ModelState.AddModelError("YourField", "Your custom message here");
}
// code
}
You can set ResourceClassKey of ClientDataTypeModelValidatorProvider class to name of a global resource that contains FieldMustBeNumeric key to replace mvc validation error message of number with your custom message. Also key of date validation error message is FieldMustBeDate.
ClientDataTypeModelValidatorProvider.ResourceClassKey="MyResources"; // MyResource is my global resource
See here for more details on how to add the MyResources.resx file to your project:
The field must be a number. How to change this message to another language?
To change the error message you get after server side validation you need to change 'PropertyValueInvalid' key in your resource file and assign the resource file name to DefaultModelBinder.ResourceClassKey. See this question for details: localize default model validation in mvc 2
Look for solution at the end of this page:
http://jwwishart.wordpress.com/2010/03/22/custom-server-and-client-side-required-validator-in-mvc-2-using-jquery-validate/
I checked this in my MVC 3 RTM project and it works well.
... or use jQuery to change to message on the client.
A quick and simple hack for Customize RangeValidator ErrorMessage --"'Field name' is not a number"-- is using RegularExpression
[Range(0.5, 1000, ErrorMessage = "Amount should be in range {1} to {2}.")]
[DataType(DataType.Currency)]
[RegularExpression(#"\d", ErrorMessage = "Amount is not valid.")]
public decimal Amount{ get; set; }
You could implement your own custom validation attribute: http://haacked.com/archive/2009/11/19/aspnetmvc2-custom-validation.aspx
It seems that since Para's answer MVC evolved and now the ClientDataTypeModelValidatorProvider accepts a ResourceClassKey property. It uses the FieldMustBeNumeric and FieldMustBeNumeric messages specified in your resource class.

Resources