Hey there StackOverflow enthusiasts.
I am attempting to update an old site of mine to the newest edition of Asp.net MVC4. It was previously on MVC2, and on MVC2 it allowed me to pretty much separate my jquery and client side stuff from any of the backend stuff. But I guess with MVC4 they want you to have a lot of your validation stuff tied directly to your models and so on.
But I have a client side jquery validation script that was working pretty well before, and I was wondering, how can I get it to work again. Specifically, I had a field that would not be validated if the user entered in more than 4000 characters. Otherwise it would not be required. Here is the client side code that worked before in MVC2....
Comment: {
required: function (element) {
return $(element).val().length > 4000;
},
maxlength: 4000
}
and the message that would be displayed if validation was not passed...
messages: {
...
Comment: 'Why dont you stop attempting to put in more than 4000 characters? Thanks...'
}
How can I do that with MVC four? To get anything to display in another field I noticed I needed to put a required over the field in my model...
[Required(ErrorMessage = "Please select an Admit Date")]
public DateTime? AdmitDate { get; set; }
Is there a way to write a requirement function so that it is only required under certain circumstances? I would prefer to keep it client side to keep my concerns separate if you know what I mean. Any help would be appreciated.
You can use [Required] and [StringLength] to constrain the input on your Comment.
[Required(ErrorMessage = "Please fill in a comment")]
[StringLength(4000, ErrorMessage = "Why dont you stop attempting to put in more than 4000 characters? Thanks...")]
public string Comment { get; set; }
Conditional required constraints are not covered by default data annotations. The default way of handling 'complex' validations is by implementing the IValidatableObject interface on your model.
However, since you are looking for a client-side solution, we can look at other frameworks that may solve this problem for you. For instance, MVC Foolproof Validation supports a [RequiredIf] attribute that also works client-side.
Related
Ecommerce web site, written using ASP.NET Core 3.1, Razor pages, EF 3.1.8 code first.
I have a model called Globals. When I first set this up, I included the default values for four of these (other properties not shown for clarity)...
[Column(TypeName = "decimal(18,2)")]
public decimal DeliveryCharge { get; set; } = 3.5M;
[Column(TypeName = "decimal(18,2)")]
public decimal FreeDeliveryOver { get; set; } = 70.0M;
public string StripePublicKey { get; set; } = "pk_test_...";
public string StripeSecretKey { get; set; } = "sk_test_...";
When I deployed the site to the production server, I manually set the two Stripe keys to the live values, so the site could take payment.
This all worked fine until one day, seemingly out of the blue, we got an exception from Stripe, as the site was using the test keys again. I checked the Globals table, and yes, the test keys were back in there.
Now there are only two of us developing this site, no-one else has access to it, so no-one has done this manually.
Baffled, I set them to the live values, somewhat worried about how this could have happened.
A week later, it happened again. A this point, it dawned on me that as the only place in the entire code base that had the test keys was this model, and the migrations that were generated, maybe EF was resetting the default values. I have no idea why this would be, as I would have thought that these values would only have bene used when the table was created, or these properties modified.
However, I removed them from the model, hoping that this would solve the problem.
Thankfully, the values on the live site have not been changed again, but I just ran the project in Visual Studio, and got an error as the Stripe keys in my local Globals table were null, presumably as I had removed the default values.
The odd thing is that the two decimal properties in there did not have their values reset to the defaults. I know this, as the FreeDeliveryOver one was changed to 50.0M shortly after we launched.
Anyone any idea what's going on here? I'm now worried that the live site is going to have the keys set to null, breaking the site when I'm not looking.
Is there any part of the app where you seed initial data?
Try to search the db table's entity name, to see if there is any programatic initalization.
Since the entity's default constructor would assign the values, is there any place where a new instance of this class is created? if so, you might have code where a new instance is returned with the default values, and later maybe attached and saved to the context by accident.
Does "globals" have row id's? are you referencing the same id when working with them and load them in the context?
( i will delete if non of the above is the case... )
After reading again the part where the decimals have stayed in place, is there any part where you update the values, but dont assign the string fields correctly? Dont forget that an update will go over the whole object, if its just .Update(data);
Before you start reading: I have looked at the GraphQL documentation, but my usecase is so specific and I only need the data once, and therefore I allow myself to ask the community for help on this one to save some time and frustration (not planning to learn GraphQL in the future)
Intro
I am a CS student developing an app for Flutter on the side, where I need information about the name and location of every bus stop in a specific county in Norway. Luckily, there's an open GraphQL API for this (API URL: https://api.entur.io/stop-places/v1/graphql). The thing is, I don't know how to query a GraphQL API, and I do not want to spend time learning it as I am only going to fetch the data once and be done with it.
Here's the IDE for the API: https://api.entur.io/stop-places/v1/ide
And this is the exact query I want to perform as I want to fetch bus stops located in the county of Trondheim:
{
stopPlace(stopPlaceType: onstreetBus, countyReference: "Trondheim") {
name {
value
}
... on StopPlace {
quays {
geometry {
coordinates
}
}
}
}
}
The problem with this query though, is that I don't get any data when passing "Trondheim" to the countyReference (without countyReference I get the data, but not for Trondheim). I've tried using the official municipal number for the county as well without any luck, and the documentation of the API is rather poor... Maybe this is something I'll have to contact the people responsible for the API to figure out, which shouldn't be a problem.
But now back to the real problem - how can I make this query using the GraphQL package for Dart? Here's the package I'm planning to use: (https://pub.dev/packages/graphql)
I want to create a bus stop object for each bus stop, and I want to put them all in a list. Here is my bus stop model:
class BusStop with ChangeNotifier {
final String id;
final String name;
final LatLng location;
BusStop({
this.id,
this.name,
this.location
});
}
When it comes to authentication, here's what the documentation says:
This API is open under NLOD licence, however, it is required that all consumers identify themselves by using the header ET-Client-Name. Entur will deploy strict rate-limiting policies on API-consumers who do not identify with a header and reserves the right to block unidentified consumers. The structure of ET-Client-Name should be: "company - application"
Header examples: "brakar - journeyplanner" "fosen_utvikling - departureboard" "norway_bussekspress - nwy-app"
Link to API documentation: https://developer.entur.org/pages-nsr-nsr
Would be great to know how I should go about this as well! I'm grateful for every answers to this, I know I am being lazy here as of learning GraphQL, but for my usecase I thought it would take less time and frustration by asking here!
Getting the query right
First of all you seem to have GraphQL quite figured out. There isn't really much more to it than what you are doing. What queries an API supports depends on the API. The problem you seem to have is more related to the specific API that you are using. I might have figured the right query out for you and if not I will quickly explain what I did and maybe you can improve the query yourself:
{
stopPlace(stopPlaceType: onstreetBus, municipalityReference: "KVE:TopographicPlace:5001") {
name {
value
}
... on StopPlace {
quays {
geometry {
coordinates
}
}
}
}
}
So to get to this I started finding out more about "Trondheim" bei using the topographicPlace query.
{
topographicPlace(query: "Trondheim") {
id
name {
value
}
topographicPlaceType
parentTopographicPlace {
id
name {
value
}
}
}
}
If you do that you will see that "Trondheim" is not a county according to the API: "topographicPlaceType": "municipality". I have no idea what municipality is but the is a different filter for this type on the query that you provided. Then putting "Trondheim" there didn't yield any results so I tried the ID of Trondheim. This now gives me a bunch of results.
About the GraphQL client that you are using:
This seems to be an "Apollo Client" clone in Dart. Apollo Client is a heavy piece of software that comes with a lot of awesome features when used in a frontend application. You probably just want to make a single GraphQL request from a backend. I would recommend using a simple HTTP client to send a POST request to the GraphQL API and a JSON body (don't forget content type header) with the following properties: query containing the query string from above and variables a JSON object mapping variable names to values (only needed if you decide to add variables to your query.
I'm using entity framework v6.2.0 and ASP Net MVC to create a web page to access a database and edit the entries. The overwhelming majority of the code is the basic framework provided for me. The database is connected successfully and entries can be viewed, edited, and deleted. Additionally I have implemented some rudimentary paging, searching, and sorting as instructions are provided by microsoft on how to implement those. The last thing I need to do before the site is truly functional is to pull the userID from the users login and save that as the EnteredBy field before saving any changes or new entries to the table.
if (ModelState.IsValid)
{
string currentUserId = User.Identity.GetUserId();
yasukosKitchen.EnteredBy = currentUserId;
db.YasukosKitchens.Add(yasukosKitchen);
db.SaveChanges();
return RedirectToAction("Index");
}
This code seems very simple, and I added using Microsoft.AspNet.Identity; so it compiles fine. However when I attempt to test this code the EnteredBy field is left blank or null.
My search for information turned up a post suggesting the use of the following line of code.
ApplicationUser currentUser = db.Users.FirstOrDefault(x => x.Id == currentUserId);
However when I attempt to add that I get an error, the ApplicationUser cannot be found and Users does not exist in this context. The fix for this is probably staring me in the face but my lack of experience and comprehension is killing me.
As suggested: My question is, how do I get and/or correctly add the UserId to my database entry?
If your Database Context has an entry to your YasukosKitchen table; usually something like this,
public virtual DbSet<YasukosKitchen> YasukosKitchens {get; set;}
and YasukosKitchen table has a column 'EnteredBy' (string 128 length), then you can post the value for the logged in user's Id straight from the View.
Add this to the very beginning of the Create view.
#using Microsoft.AspNet.Identity
#using Microsoft.AspNet.Identity.EntityFramework
At the end of the form just before the submit button, add this code.
#Html.HiddenFor(model => model.EnteredBy, new { #Value = User.Identity.GetUserId() })
I'm not sure what is the functionality of 'Users' table.
I am using ASP.Net MVC 4 and created model and validation like this
[Required]
[Display(Name = "Full Name")]
[StringLength(50)]
[RegularExpression("^[a-zA-Z0-9 -']+$", ErrorMessage = "Invalid {0}")]
public String FullName { get; set; }
It is validating properly on clint side.
I am already checking
if(!ModelState.IsValid)
return View(Model);
But when validating with IBM AppScan, it posts data directly like John' or 1 = 1 -- and shows issue of Blind Sql Injection.
Debug the code and try to change the full name value to John' or 1 = 1 -- and ModelState is still showing valid.
I want to validate the model RegEx in controller, is there any way to validate it in controller?
Blind SQLi testing is often a hit & miss in terms of automated application security test tools. Try to do a retest in appscan using a single thread on the Blind SQLi issue and see if it'd just simply be removed as false positive.
I'm exploring using FluentValidation as it seems to be an elegant API for validation of my ViewModels upon model binding. I'm looking for opinions on how to properly centralize validation using this library as well as from my business (service) layer and raise it up to the view without having 2 different approaches to adding modelstate errors.
I'm open to using an entirely different API but essentially looking to solve this branching validation strategy.
[Side Note: One thing I tried was to move my business method into my FluentValidation's custom RsvpViewModelValidator class and using the .Must method but it seemed wrong to hide that call in there because if I needed to actually use my Customer object they I would have to re-query it again since its out of scope]
Sample Code:
[HttpPost]
public ActionResult AcceptInvitation(RsvpViewModel model)
{
//FluentValidation has happened on my RsvpViewModel already to check that
//RsvpCode is not null or whitespace
if(ModelState.IsValid)
{
//now I want to see if that code matches a customer in my database.
//returns null if not, Customer object if existing
customer = _customerService.GetByRsvpCode(model.RsvpCode);
if(customer == null)
{
//is there a better approach to this? I don't like that I'm
//splitting up the validation but struggling up to come up with a
//better way.
ModelState.AddModelError("RsvpCode",
string.Format("No customer was found for rsvp code {0}",
model.RsvpCode);
return View(model);
}
return this.RedirectToAction(c => c.CustomerDetail());
}
//FluentValidation failed so should just display message about RsvpCode
//being required
return View(model);
}
[HttpGet]
public ActionResult CustomerDetail()
{
//do work. implementation not important for this question.
}
To give some closure to the question (and make it acceptable) as well as summarize the comments:
Business/process logic and validation logic are two entities. Unless the validation ties in to the database (e.g. check for unique entries) there's no reason to group validation into one location. Some are responsible in the model making sure there's nothing invalid about the information, and some handle how the validated values are used within the system. Think of it in terms of property getters/setters vs the logic used in the methods with those properties.
That being said, separating out the processes (checks, error handling, etc.--anything not relating to UI) can be done in a service layer which also tends to keep the application DRY. Then the action(s) is/are only responsible for calling and presenting and not performing the actual unit of work. (also, if various actions in your application use similar logic, the checks are all in one location instead of throw together between actions. (did I remember to check that there's an entry in the customer table?))
Also, by breaking it down in to layers, you're keeping concerns modular and testable. (Accepting an RSVP isn't dependent on an action in the UI, but now it's a method in the service, which could be called by this UI or maybe a mobile application as well).
As far as bubbling errors up, I usually have a base exception that transverses each layer then I can extend it depending on purpose. You could just as easily use Enums, Booleans, out parameters, or simply a Boolean (the Rsvp either was or wasn't accepted). It just depends on how finite a response the user needs to correct the problem, or maybe change the work-flow so the error isn't a problem or something that the user need correct.
You can have the whole validation logic in fluent validation:
public class RsvpViewValidator : AbstractValidator<RsvpViewModel>
{
private readonly ICustomerService _customerService = new CustomerService();
public RsvpViewValidator()
{
RuleFor(x => x.RsvpCode)
.NotEmpty()
.Must(BeAssociatedWithCustomer)
.WithMessage("No customer was found for rsvp code {0}", x => x.RsvpCode)
}
private bool BeAssociatedWithCustomer(string rsvpCode)
{
var customer = _customerService.GetByRsvpCode(rsvpCode);
return (customer == null) ? false : true;
}
}