MVC4 custom unobtrusive validator isn't working - asp.net-mvc-4

not sure what is wrong. Syntax seems correct.... but it still doesn't fire on client side. If I submit the form, I get server side validation, client side nothing...
Here is the code that is on the page:
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")"></script>
<script type="text/javascript">
// we add a custom jquery validation method
(function ($) {
$.validator.addMethod('additive', function (value, element, params) {
//just return false to test it.
return false;
});
// and an unobtrusive adapter
$.validator.unobtrusive.adapters.add("additive", ["field2", "field3", "field4"], function (options) {
var params = {
field2: options.params.field2,
field3: options.params.field3,
field4: options.params.field4
};
options.rules['additive'] = params;
if (options.message) {
options.messages['additive'] = options.message;
}
});
}) (jQuery);
</script>
Here is the part that is on the validator that is related to client side (IClientValidatable):
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
ModelClientValidationRule rule = new ModelClientValidationRule
{
ValidationType = "additive",
ErrorMessage = "ERROR MESSAGE"
};
rule.ValidationParameters.Add("field2", propName2);
rule.ValidationParameters.Add("field3", propName3);
rule.ValidationParameters.Add("field4", propName4);
yield return rule;
}
The model is decorated as following:
[SumValidation("OtherField2...")]
public int MyField { get; set; }
When field renders, it is all there, all the stuff from the server side in terms of data-xxx attributes. Just this specific client validation does not fire. Anyone see what I'm missing?

figured it out. If anyone runs into this. Added custom validation too late on the page. After I moved my custom validation javascript to the head section of the _Layout.cshtml it started to work.
So if your script looks right, good place to check.
Another work around is to run $.validator.unobtrusive.parse('form'); which reloads all the validators.

Related

How to fetch initial data using provider in flutter effectievly

Recently, i did a flutter course.
The instructor was making the get request from an API so difficult. For a hybrid framework like flutter i never thought it's so difficult.
below are my code. I am using provider for state management.
Future<void> fetchAndSetProducts() async {
try {
const url = 'fetch-url';
final response = await http.get(url);
final data = json.decode(response.body) as Map<String, dynamic>;
final List<Product> loadedProducts = [];
data.forEach((key, value) {
loadedProducts.add(Product(
id: key,
title: value['title'],
description: value['description'],
imageUrl: value['imageUrl'],
price: value['price'],
isFavorite: value['isFavorite'],
));
});
_items = loadedProducts;
notifyListeners();
} catch (error) {
throw (error);
}
}
And in the products overview screen were I am showing the products page this method is called like below:
bool _isInit = true;
bool _isLoading = false;
#override
void didChangeDependencies() {
if (_isInit) {
setState(() {
_isLoading = true;
});
Provider.of<Products>(context).fetchAndSetProducts().then((_) => {
setState(() {
_isLoading = false;
})
});
}
_isInit = false;
super.didChangeDependencies();
}
The other method included a sneaky way of using duration of zero just like we use in javascript set timeout giving a zero time.
It's worth noting that in didChangeDependencies we could not use async await, so most probably a call back hell awaits.
Also a variable needs to be initialized just for calling the api once upon loading.
Is there no easy solution to this? Or an industry way of dealing with this?
here is a minimal working example of what you can do, it's not the best thing in the world, but this is what works for me, let me know if you can make it any better.
The answer to your problem is really simple, BUT, you need to rearrange some stuff first.
A Flutter app can be split into multiple layers which are (just for example) data, state management and UI, in the data layer you will have all methods that communicate with the API, and you call them inside the state management solution (which is provider in your case), the result will be accessible from the provider which will save the data in a variable, then the UI will be able to retrieve these data from the provider, this seems a bit redundant I know, but there is a reason why we do that, if you put the API call inside the provider itself, and there is somewhere else in your app that uses the same endpoint then you will have duplicate code, as for the provider, it's the place where your data is stored in the runtime, these data are what makes the state of your app, finally, the UI can handle displaying data from the provider easily, just make a boolean in the provider that indicates if the API call is executing/loading or not, and inside the consumer in the UI display different widgets based on the boolean.
If we were to visualize the flow of the operation it would be like this:
1- action from the UI that triggers a method from the provider.
2- inside the provider method you will set the boolean indicating that the API call is executing to true and call notifyListeners().
3- call the API request and call .then() on it.
4- inside the .then() set the boolean to false to notify that the call is over and set the received data to a variable inside the provider and call notifyListeners again.
5- in the UI you should have a consumer listening to your provider and handling the boolean, if its true then display a CircularProgressIndicator for example, and if it's false then display your desired widget
Regarding the context in the initState you can fix this problem in 3 ways:
1- using WidgetsBinding.instance
.addPostFrameCallback((_) => yourProviderFunction(context));
2- by registering your provider in a service locator so you don't have to use a context at all. (which is what I used in the example project I posted above)
3- by executing the desired function in the constructor of the provider, so when its initialized the API request will be called
Is this the Academind course?
Also this is the correct way.
For using a Provider you need the context.
EDIT: Added BaselAbuhadrous' comment to the answer.
You need to use didChangeDependencies because the initState actually provides the context, but the screen layout isn't built yet, so you get an error, but if you used WidgetsBindings.instance and call the provider inside of it, then you won't get the error.
//your model , product_model.dart
import 'dart:convert';
List<Product> availableTicketsFromJson(String str) => List<Product>.from(json.decode(str).map((x) => Product.fromJson(x)));
class Product {
String title;
String description;
String imageUrl;
double price;
bool isFavorite;
Product(
{this.title,
this.description,
this.imageUrl,
this.price,
this.isFavorite});
factory Product.fromJson(Map<String, dynamic> json) => Product(
title: json['title'] as String,
description: json['description'] as String,
imageUrl: json['imageUrl'] as String,
price: json['price'] as double,
isFavorite: json['isFavorite'] as bool,
);
}
//viewmodel class
final String url = "test.com";
Future<List<Product> fetchProducts() async {
List<Product> products = List<Product>();
try {
final request = await http.get(url);
if(request.statusCode == 200) {
products = productsFromJson(request.body.toString());
notifyListeners();
} else {
print(request.statusCode.toString());
}
} catch(e) {
return List<Product>();
}
return products;
}
//fetch_data.dart
Create your instance of provider in the page that you wanna fetch the data:
Under State<yourWidget>
=> FetchDataViewModel _model;
List<Product> products = [];
under build method
=> _model = Provider.of<FetchDataViewModel>(context,listen: false);
Make a http request with FutureBuilder
FutureBuilder(future:_model.fetchProducts()),
builder: (context,snapshot)){
if(snapshot.connectionState == ConnectionState.done) {
products = snapshot.data;
if(products.length > 0) {
return ListView.builder(
itemCount: products.length,
itemBuilder : (context,index) {
return _items();
}
);
} else {return _noSavedDataWidget();}
}
}
You can test such a code
sometimes
Provider.of<'providerClassName'>(context, listen : false).'providerFunction'
might help.

How can I change css directly(without variable) in Blazor?

I am using the server-side of Blazor.
I want to change the CSS of the body.
In Jquery I can write the code like this easily:
$("body").css("overflow-y","hidden");
However, with this tutorial(Blazor Change Validation default css class names) said, it seems I can only change the CSS by changing the class name.
It is so complex while crossing the component, especially the body is at the top of all the components.
I wonder whether there is a way can changes CSS directly in Blazor. Thank you.
There are several ways of getting out of the "blazor way" of doing things and accomplishing css modification of an element.
Simplest: Just like you can use the class attribute, use the style attribute
<element style=#myStyle></element>
#code {
string myStyle;
void MyMethod() {
myStyle="overflow-y: hidden;"
}
}
Advanced: Use JS interop
a. In the main view (index.html or Pages/_Host.cshtml depending on project type), create a js endpoint for your component
<script>
window.applyStyleForElement = function(styleOp) {
document.getElementById(styleOp.id).style[styleOp.attrib] = styleOp.value;
}
</script>
b. In razor file:
#Inject IJRRuntime JSRuntime
<element id=#myId></element>
#code {
string myId = Guid.NewGuid().ToString("n");
async Task MyMethod() {
await JSRuntime.InvokeAsync("applyStyleForElement",
new { id = myId, attrib = "overflowY", value = "hidden" });
}
}
Finally, applying to your special case with body element ("advanced" method above).
a. In the main view (index.html or Pages/_Host.cshtml depending on project type), create a js endpoint
<script>
window.applyStyleForBody = function(style) {
document.body.style[style.attrib] = style.value;
}
</script>
b. In razor file:
#Inject IJRRuntime JSRuntime
(...)
#code {
async Task MyMethod() {
await JSRuntime.InvokeAsync("applyStyleForBody",
new { attrib = "overflowY", value = "hidden" });
}
}
Well, Blazor does not support direct css modification yet, since Web Assembly doesn't. Anyway heads up, it is on the road-map for Web Assembly/Blazor.
Therefor your best bet is, changing the class name with variables. At least for now.
I'M NOT SURE IT'S THE RECOMMENDED WAY BUT it works!
For one of my project, I include a in the page html itself, using params :
<style>
html
{
background-color:#_ColorCss;
}
</style>
//html stuff here
#code
{
public string Color{ get; set; } = "white";
string _ColorCss => $"{Color}"; //use this in case of formatting (ex : add 'px' or that kind of things)
//code stuff here
}
not the very sexiest way but it works
have fun !
Well, actually there is a way to do that and it works really good (it might suffer a little delay though).
I know this answer is a little bit late but it might help other people who face the same challenge.
We need to create some JS code that includes the wanted files:
function includeLeftStyle() {
appendStyle("left.css");
}
function includeRightStyle() {
appendStyle("right.css");
}
function appendStyle(path) {
var element = document.createElement("link");
element.setAttribute("rel", "stylesheet");
element.setAttribute("type", "text/css");
element.setAttribute("href", path);
document.getElementsByTagName("head")[0].appendChild(element);
}
The wished CSS can be called according to the language (any other coditions) in the MainLayout:
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
if (// is left)
{
await JSRuntime.InvokeAsync<object>("includeLeftStyle");
}
else
{
await JSRuntime.InvokeAsync<object>("includeRightStyle");
}
}
}
Happy coding! :)
Beginnig from the #Tewr answer, we can also change the whole class:
a) In the main view (index.html or Pages/_Host.cshtml depending on project type), create a js endpoint
<script>
window.applyStyleForElement = function (styleOp) {
if (styleOp != null) {
document.getElementById(styleOp.id).className = styleOp.value;
}
}
</script>
b) Then in the razor file
async Task MyMethod(string sortColumn)
{
await JsRuntime.InvokeVoidAsync("applyStyleForElement",
new { id = sortColumn, value = "newClassName" });
}

Aurelia DataTables Recompile

I've been exploring Aurelia and so far have loved what I've seen. I've come accross an issue that I'm not really sure how to solve. I used jquery datatables for large results in my current app with angular, using server side fetches. Datatables has a function you can call whenever a new row is added to the table (fnRowCallback - http://legacy.datatables.net/ref#fnRowCallback, or "createdRow" - https://datatables.net/examples/advanced_init/row_callback.html#) - This is really handy as you can recompile the dom after each row (costly I know).
This enables you to reference functions that exist in the current scope (or viewModel) that the datatable exists in. For example:
In my view model:
export class DataTableTest{
test(){
alert('this is a test');
}
}
In the return results from a datatable fetch:
{name:'blah',age:40,actions:"<a click.delegate='test();'>Test</a>"}
For some reason I can't seem to figure out how to recompile an element once it has been added to the dom.
Does anyone have any ideas how you could do this?
UPDATE:
These are the original options I pass to datatables:
var options = {
"fnRowCallback": function (nRow) {
$compile($(nRow).contents())(scope);
}
};
I've tried the following after injecting that compiler service:
"fnRowCallback": function (nRow) {
this.compiler.compile($(nRow).contents()).fragment.innerHTML;
},
But I always get Uncaught TypeError: Cannot read property 'compile' of undefined - I do this in the "attached" function.. If I console.log(this.compiler) outside of these options, it's available. Also, we don't need to return html back to datatables, just run the compile on the contents. Many thanks for all your help!
You can use a compiler service to compile the element:
import {inject, ViewCompiler, ViewResources, Container} from 'aurelia-framework';
/**
* Compiler service
*
* compiles an HTML element with aurelia
*/
#inject(ViewCompiler, ViewResources, Container)
export class Compiler {
viewCompiler: any;
resources: any;
container: any;
constructor(viewCompiler, resources, container) {
this.viewCompiler = viewCompiler;
this.resources = resources;
this.container = container;
}
compile(templateOrFragment, ctx = null, viewSlot = null):any {
if (typeof templateOrFragment === "string") {
var temp = document.createElement('span');
temp.innerHTML = templateOrFragment;
templateOrFragment = temp;
}
var view = this.viewCompiler.compile(templateOrFragment, this.resources).create(this.container, ctx);
return view;
}
}
I use this in Kendo in the cell template callback function (it lets you return a string that will become the cell contents)
function(dataItem) {
var cellctx = { "$item": dataItem, "$parent": ctx };
return this.compiler.compile(templateString, cellctx).fragment.innerHTML;
}
(this happens in Aurelia's bind callback so the ctx is the executionContext)
I just wrap the current data item up in a context and alias it as $item so I can work with it.
Looks something like this:
<kendo-grid>
<kendo-grid-col title="Main Office" field="IsMainOffice">
<kendo-template><img if.bind="$item.IsMainOffice" src="/content/img/accept.png" /></kendo-template>
</kendo-grid-col>
</kendo-grid>

Implementing an asynchronous call to a long running process MVC4

I have a large data set that holds up my UI so I thought I would create a background call to fill my local repository and display my other controls in the UI right away and load the results of the async call when I get a response.
I found a helpful tutorial but I am still having to wait until all my results are loaded before I see any controls.
http://www.asp.net/mvc/tutorials/mvc-4/using-asynchronous-methods-in-aspnet-mvc-4
CODE UPDATED
I have created a folder called Services and created FacilitiesService.cs in that folder, see below:
public class FacilitiesService
{
internal async Task<List<Facility>> GetFacilitiesBySourceDbAsync(string sourceDb)
{
var fac = new Facility();
var con = Connect(); // Omitted
try
{
con.Open();
}
catch (Exception ex)
{
Console.WriteLine("Error: GetFacilityBySourceDb " + ex.Message);
}
try
{
OracleDataReader reader = null;
// Requestor
var cmd = new OracleCommand("SELECT FACILITY, FACILITY_ID FROM MyTable where (source_db = '" + sourceDb + "')", con);
reader = cmd.ExecuteReader();
while (reader.Read())
{
fac.Add(new Facility()
{
FacilityName = reader["FACILITY"].ToString(),
FacilityId = reader["FACILITY_ID"].ToString()
});
}
}
catch (Exception ex)
{
throw ex;
}
finally
{
con.Close();
con.Dispose();
}
return fac;
}
}
Then in my HomeController.cs I have the following:
public class HomeController
{
public async Task<List<Facility>> FacilitiesAsync()
{
ViewBag.SyncOrAsync = "Asynchronous";
var service = new FacilitiesService();
this._facilities = new List<Facility>();
var facilities = await service.GetFacilitiesBySourceDbAsync("TEST");
foreach (var item in facilities)
{
Facility fac = new Facility()
{
FacilityName = item.FacilityName,
FacilityId = item.FacilityId
};
_facilities.Add(fac);
}
return _facilities;
}
}
This is my Facility (model) class:
public class Facility : List<Facility>
{
[Required]
[Display(Name = "Facility")]
public string FacilityName { get; set; }
public string FacilityId { get; set; }
public Facility()
{
// Default Constructor
}
public Facility(string facilityName, string facilityId)
{
this.FacilityName = facilityName;
this.FacilityId = facilityId;
}
}
I am using an Ajax call to kick off the FacilitiesAsync method in the code behind from a function call in the About.cshtml page when the user tabs off the tetbox/input control with an id of "tags", I could switch this to something else later but I get the data back when I step through the code-behind and I see both the beforeSend and complete functions fire an alert:
<script type="text/javascript">
$(function () {
var availableTags = [
// Neeed data from function call to populate this list
];
$("#tags").autocomplete({
source: availableTags
});
$("#tags").focusout(function () {
var result = null;
$.ajax({
beforeSend: function() {
alert("Testing");
},
url: "FacilitiesAsync",
success: function(data) {
result = data;
},
complete: function () {
alert(result);
}
});
});
});
</script>
#using (Html.BeginForm()) {
<div class="ui-widget">
<label for="tags">Tags: </label>
<input id="tags" />
</div>
}
This works GREAT! However, I want to take the data from the call made to the code-behind to populate the array availableTags and I'm not sure how to do that. Suggestions?
There's a few things wrong with the implementations, and one problem with the approach.
First, the GetFacilitiesBySourceDbAsync does not contain an await. The compiler will issue a warning in this situation, informing you that it's not really an asynchronous method when you do that; it will run synchronously. That's an important warning. If you want asynchronous code, you'll need to make it asynchronous all the way. This means using the asynchronous database methods (ExecuteReaderAsync, etc).
Secondly, the Task.WhenAll call in Index is meaningless (since you only pass it a single task). Also, since Index is synchronous but calls an asynchronous method, the code not shown is probably calling Result, which is a no-no on ASP.NET. As I explain on my blog, this will actually deadlock once your async code is actually asynchronous.
But even if you fix these, it won't do what you want. There's a problem with the approach, and that is that async doesn't change the HTTP protocol (this is also a link to my blog). ASP.NET MVC understands asynchronous methods and will not complete the request until the async action method completes. You'll need to use something like AJAX to get the web page to do what you want.

How to get AntiForgeryToken value without hidden input

#Html.AntiForgeryToken()
renders hidden input
<input name="__RequestVerificationToken" type="hidden" value="GuiNIwhIJZjINHhuS_8FenaFDXIiaE" />
How can I get token value only?
Without ugly code like this:
public static IHtmlString AntiForgeryTokenValue(this HtmlHelper htmlHelper) {
var field = htmlHelper.AntiForgeryToken().ToHtmlString();
var beginIndex = field.IndexOf("value=\"") + 7;
var endIndex = field.IndexOf("\"", beginIndex);
return new HtmlString(field.Substring(beginIndex, endIndex - beginIndex));
}
The anti-CSRF capabilities of MVC actually depend on two tokens: one is a hidden form element, and the other is a cookie. So the Html.AntiForgeryToken() helper doesn't just return an HTML snippet. It also has a side effect of setting this cookie. Note that the cookie value and the form value are not equal since they each encode different pieces of information.
If you use the AntiForgery.GetTokens API, this method will return the raw tokens instead of generating an HTML snippet. The parameters to this method are:
oldCookieToken: If the request already contains an anti-CSRF cookie token, provide it here. This parameter may be null.
newCookieToken (out parameter): If oldCookieToken was null or did not represent a valid anti-CSRF cookie token, this parameter will be populated with the value that you should put in the response cookie. If oldCookieToken represented a valid anti-CSRF token, then newCookieToken will contain null when the method returns, and you don't have to set a response cookie.
formToken (out parameter): This parameter will be populated with the token that should be present in the form body when posting back to the server. This is the value that ends up being wrapped by the hidden input element in a call to Html.AntiForgeryToken().
If you use this API to generate cookie and form tokens manually, you'll need to call the corresponding overload of AntiForgery.Validate in order to validate the tokens.
I realize this question is old, but based on what I read here I came up with a reasonably simple solution that seems to work for me. I'm using it on an AngularJS SPA that uses partial templates, only some of which involve POST submissions.
I put this code at the top of view:
#{
string cookieToken, formToken;
string oldCookieToken = Request.Cookies[AntiForgeryConfig.CookieName] == null ? null : Request.Cookies[AntiForgeryConfig.CookieName].Value;
AntiForgery.GetTokens( oldCookieToken, out cookieToken, out formToken );
if( oldCookieToken == null )
{
Request.Cookies.Add( new HttpCookie( AntiForgeryConfig.CookieName, cookieToken ) );
}
else
{
Request.Cookies[AntiForgeryConfig.CookieName].Value = cookieToken;
}
}
and then wherever I need the form's antiforgery token (e.g., in an ajax or angularjs POST) I just include '#formToken' in the headers:
$http.post(route, JSON.stringify(args), {
headers: {
'#AntiForgeryConfig.CookieName': '#formToken',
'Content-Type': 'application/json; charset=utf-8',
},
});
Note that because in this example I'm expecting JSON data back from my action method I also had to implement anti-forgery validation based on headers, not form fields. There's a nice post about this at http://johan.driessen.se/posts/Updated-Anti-XSRF-Validation-for-ASP.NET-MVC-4-RC.. Here's the implementation:
[AttributeUsage( AttributeTargets.Method | AttributeTargets.Class,
AllowMultiple = false, Inherited = true )]
public sealed class ValidateJsonAntiForgeryTokenAttribute
: FilterAttribute, IAuthorizationFilter
{
public void OnAuthorization( AuthorizationContext filterContext )
{
if( filterContext == null )
{
throw new ArgumentNullException( "filterContext" );
}
var httpContext = filterContext.HttpContext;
var cookie = httpContext.Request.Cookies[AntiForgeryConfig.CookieName];
AntiForgery.Validate( cookie != null ? cookie.Value : null,
httpContext.Request.Headers[AntiForgeryConfig.CookieName] );
}
}
and here's how it's used:
[HttpPost]
[ValidateJsonAntiForgeryToken]
public JsonResult RecordVisit( VisitInfo info )
This is a bit old, but i found no real answers for this one. I peeked around and found this solution. I need the formtoken in an javascriptobject, so this helper came in handy.
public static class AntiForgeryHtmlExtensions
{
public static string AntiForgeryFormToken(this HtmlHelper helper)
{
string cookieToken, formToken;
AntiForgery.GetTokens(null, out cookieToken, out formToken);
HttpContext.Current.Response.Cookies.Set(new HttpCookie(AntiForgeryConfig.CookieName, cookieToken));
return formToken;
}
}
As #Levi mentioned, calling GetTokens, has sideeffects, so we have to set the response-cookie before returning the token.
For asp.net core use dependency injection to get IAntiforgery and then call GetAndStoreTokens
public class TestController
{
public TestController(IAntiforgery antiforgery)
{
var tokens = antiforgery.GetAndStoreTokens(HttpContext);
}
}
If using core you can do this in the layout or razor page like so:
#inject Microsoft.AspNetCore.Http.IHttpContextAccessor HttpContextAccessor
#inject Microsoft.AspNetCore.Antiforgery.IAntiforgery Antiforgery
#{
var afToken = Antiforgery.GetAndStoreTokens(HttpContextAccessor.HttpContext!).RequestToken;
}
<html lang="en">
<head></head>
<body>
<script type="text/javascript">
window.XCSRF = '#afToken';
console.log(window.XCSRF);
</script>
now you can access the token using javascript window.XCSRF variable