MVC5 Microsoft.CSharp.RuntimeBinder.RuntimeBinderException - asp.net-mvc

Ive been working on converting a MVC4 project over to MVC5. The first day I ran into an 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException' but was able to resolve it by starting my conversion over. I'm not sure what the fix was which is a bummer, because its happened again.
The Error occurs in _ExternalLoginsListPartial.cshtml when I load the Login.cshtml page. The error is thrown on line 15. (string action = Model.Action;)
#using Microsoft.Owin.Security
#{
var loginProviders = Context.GetOwinContext().Authentication.GetExternalAuthenticationTypes();
var authenticationDescriptions = loginProviders as AuthenticationDescription[] ?? loginProviders.ToArray();
if (!authenticationDescriptions.Any())
{
<div>
<p>There are no external authentication services configured. See this article
for details on setting up this ASP.NET application to support logging in via external services.</p>
</div>
}
else
{
string action = Model.Action;
string returnUrl = Model.ReturnUrl;
using (Html.BeginForm(action, "Account", new { ReturnUrl = returnUrl }))
{
#Html.AntiForgeryToken()
<div id="socialLoginList">
<p>
#foreach (AuthenticationDescription p in authenticationDescriptions)
{
<button type="submit" class="btn btn-default padded-8 margin-8" id="#p.AuthenticationType" name="provider"
value="#p.AuthenticationType" title="Log in using your #p.Caption account">
<img src="#Url.Content("~/Content/Brands/"+p.Caption+".png")" alt="Microsoft" class="img-responsive" />
<br/>
<b>#p.Caption</b>
</button>
}
</p>
</div>
}
}
}
The error thrown is
An exception of type 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException' occurred in System.Core.dll but was not handled in user code
Additional information: 'object' does not contain a definition for 'Action'
The snapshot says
Message : object' does not contain a definition for 'Action'
Source : Anonymously Hosted DynamicMethods Assembly
Now this is double weird because when I set a breakpoint Model.Action is not null. I can see the value.
This is really frustrating. The app was working 5 min ago.. I had changed the html on a non related page.. and now it wont work.
Hackish Fix
I would rather know why this error is happening. That said, I have a quick fix in case anyone else comes across this (Because this is part of part of the default solution). The solution is to not use dynamics. Create your own viewmodel and pass that.
public class ExternalLoginViewModel
{
[Display(Name = "ReturnUrl")]
public string ReturnUrl { get; set; }
[Required]
[Display(Name = "Action")]
public string Action { get; set; }
}
#Html.Partial("_ExternalLoginsListPartial", new ExternalLoginViewModel { Action = "ExternalLogin", ReturnUrl = ViewBag.ReturnUrl })

Check the views in the Account folder and for each one that has an explicit model, make sure the (view)model is in the right namespace. Mouse over the m parameter (m => m.UserName ... etc) and make sure it is referencing the correct (view)model.
In my case, I moved AccountViewModels to a different folder and the app broke as above. It appears the views are sort of "caching" the model from the original namespace. I used a silly fix (commented out the #model line and un-commented it back). Got warning that m is dynamic but when built and ran it worked. Looks like a glitch in VS 2013 RTM.

This bug is verified by Microsoft, and they are working on fixing it.
So anyone from the future who reads this: try updating visual studio 2013 to at least update 2.
https://connect.microsoft.com/VisualStudio/feedback/details/813133/bug-in-mvc-5-framework-asp-net-identity-modules

Found a solution for my own (mvc5) project after some experimenting.
I had a _ExternalLoginsListShoppingCartPartial.cshtml (from my mvc4 project) with #model ICollection<AuthenticationClientData> at the top. I commented it out and rebuild the solution and suddenly it works. I'm not even using that partial view in any view so it's a pretty nasty bug imo.
So check in your project. You may have some mvc4/simplemembership stuff that is messing up your mvc5 project.

I got the same error after replacing account models to another folder. When I double checked each view under the Account folder I found out my "Manage.cshtml" referenced to old namespace. I changed it to correct namespace for my models and the error fixed.

For me I had changed the contents of the ManageUserViewModel to add a property... I then started getting the error. When I changed the Manage.cshtml from not using an explicit model to using:
#model XYZ.Models.ManageUserViewModel
and removed the using statements, it started working again. One hour wasted!

I also hit this issue with VS 2013 U3. I had just added an email field to RegisterViewModel with the [EmailAddress] attribute, and it was crashing when I tried visiting the Register page. Commenting out the [EmailAddress] attribute fixed the issue. However, it continued working after I added the attribute back in, so this is probably a broader issue that could have to do with changes to the model classes.

yeah, I replaced the "else" code with the following and its working but still trying to see why it didn't work when using Model.Action ?
//string action = Model.Action;
//string returnUrl = Model.ReturnUrl;
//using (Html.BeginForm(action, "Account", new { ReturnUrl = returnUrl }))
using (Html.BeginForm("ExternalLogin", "Account", new { ReturnUrl = ViewBag.ReturnUrl }))

Related

How do I set the locale in asp.net core that my ModelBinders will use?

I am trying to force my asp.net core 3.1 application to use the locale "en-US", no matter the default locale of the Windows server it runs on.
My main goal is to have ModelBinding correctly parse doubles entered by users. So far, I did not have any luck. The comma is interpreted as the decimal separator, whereas the point is interpreted as the thousands separator, which is consistent with the Windows default locale.
So my code looks (simplified) like this:
public class Model
{
public double Percentage {get; set;}
}
[HttpPost]
public ActionResult Index(Model model)
{
Debug.WriteLine(model.Percentage);
}
This results in data entered and posted as "12.34" to be cast to double 1234, etc.
Previously, in ASP.Net MVC 5, adding this to the web.config file solved this issue:
<configuration>
<system.web>
<globalization culture="en-US" uiCulture="en-US" />
I have tried various methods described, which I will list below, but to no avail. These seem to be revolving around localization of the mark-up, but do not affect model binding.
Apply the same settings as listed above.
Adding this to the Startup's ConfigureServices() method:
System.Threading.Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
System.Threading.Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-US");
Adding this to the same method:
services.Configure<RequestLocalizationOptions>(
options =>
{
options.DefaultRequestCulture = new RequestCulture(culture: "en-US", uiCulture: "en-US");
options.SetDefaultCulture("en-US");
});
The latter attempts being merely trial-and-error.
I tried running on IIS and on IIS Express.
I do realize I could write a custom model binder, but I think this adds unneeded complexity. Also, I could skip model binding and parse the post data manually, but the actual models are extensive and contain a lot of data. I do not want to go that way.
Addendum
I could reproduce this behavior with a small demo application. Steps to reproduce:
Create a new web application in Visual Studio .Net 2019 with:
ASP.Net Core Web Application
Web Application (Model-View-Controller)
Add a view model:
public class InputModel
{
[Range(0, 1)]
public double Fraction { get; set; }
}
Replace the index.cshtml with:
#model InputModel
#using (Html.BeginForm("Index", "Home", FormMethod.Post))
{
#Html.LabelFor(m=>m.Fraction)
#Html.TextBoxFor(m=>m.Fraction)
#Html.ValidationMessageFor(m => m.Fraction)
<input type="submit" value="Submit" />
}
Add an action to the conntroller:
[HttpPost]
public IActionResult Index(InputModel input)
{
if (ModelState.IsValid)
{
return Content($"Received fraction: {input.Fraction:E3}");
}
return View(input);
}
On my development Pc:
input 0.5 is invalid and
input 0,5 is valid.
input 0,1 is valid, but the action will output:
Received fraction: 1,000E+000
Adding this to ConfigureServices in Startup.cs:
services.Configure<RequestLocalizationOptions>(
options =>
{
options.SupportedCultures = new List<CultureInfo> { new CultureInfo("en-US") };
options.SupportedUICultures = new List<CultureInfo> { new CultureInfo("en-US") };
options.SetDefaultCulture("en-US");
});
does not make a difference.
Only when I set change settings through Control Panel - Clock and Region - Change date time or number formats, can I make my web application accept the dot as the decimal separator. I do not like having to rely on that.

MVC5 : The resource cannot be found

I am fetching data from a table and displaying it. Every row in the webpage will have a edit hyperlink. That pops up a edit window for respective row. The contents of the pop up are replaced by the #Html.Partial() function. now the form gets submitted from the Partial view. The Interesting fact is first time I edit any row it works fine. However the second time I am getting the following error:
Server Error in '/' Application.
The resource cannot be found.
Description: HTTP 404. The resource you are looking for (or one of its dependencies) could have been removed, had its name changed, or is temporarily unavailable.  Please review the following URL and make sure that it is spelled correctly.
Requested URL: /Edit
Version Information: Microsoft .NET Framework Version:4.0.30319; ASP.NET Version:4.7.2623.0
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include = "SerialNumber,ProjectName,Nature,Phase,StartDate,EndDate,ProjectLead,LeadAlias,Onsite,OffShore,ProjectDetail,EditedBy,CreatedBy")] ProjectModel projectModel)
{
projectModel.EditTime = DateTime.Now;
if (ModelState.IsValid)
{
db.Entry(projectModel).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(projectModel);
}
The form gets submitted using the following button:
<input type="submit" value="Save" class="btn btn-default" formaction="Edit" formmethod="post" />
Please let me know if anything else do you need. Thanks in advance.
#shyju 's answer really helped I changed the formaction and it worked

Provider hosted asp.net mvc app upload file

I am trying to create a simple post in which I am also attaching an image using Provider Hosted App on Sharepoint online, and I am not able to get SPHostUrl at Controller in HttpContext.Request, I mean SPHostUrl is missing in HttpContext.Request.
[HttpPost]
public ActionResult Contact(SimplePostModel model,HttpPostedFileBase file)
{}
View
#using (Html.BeginForm("Contact","Home",null,FormMethod.Post,new { enctype= "multipart/form-data"}))
The question is if I am sending this part new { enctype= "multipart/form-data"} in the above mentioned statement of View, I am not able to get SPHostUrl parameter in HttpContext.Request.
If I am not sending the html attributes then I am able to get SPHostUrl parameter in HttpContext.Request. and without html attributes I am also not able to upload a file.
Thanks in Advance for your help.
I have solved the issue,by changing some piece of code on in the Razor View.
#using (Html.BeginForm("Contact","Home",null,FormMethod.Post,new { enctype= "multipart/form-data"}))
Instead of null for object route values I send the spHosturl like below.
#using (Html.BeginForm("Contact","Home",new { SPHostUrl = spUrl },FormMethod.Post,new { enctype = "multipart/form-data" }))
the spUrl value comes like below
#{
var spUrl = Request.QueryString["SPHostUrl"];
}
I hope this will help for new sharepoint online developers

Why is MVC button link inserting incorrect url

I have a simple mvc login page with a button generating an incorrect link. When I hover over the button, the link, which I believe is the default form action which in turn is the current page, is /resource.ashx?action=login&controller=user. It should be /action=login&controller=user. The url of the page is
http://localhost:57505/User/Login.
Can anyone explain how I would go about determining where / why / how resource.ashx is made part of the form submit action? and more importantly how to fix?
I have considered routing, and javascript files which may be modifying the html but nothing strikes me as a culprit.
The cshtml code is as follows:
#model MyCompany.MyApp.Website.Models.User.LoginViewModel
#{
Layout = "~/Views/Shared/_LoginLayout.cshtml";
ViewBag.Title = "Log in";
}
#using (Html.BeginForm(new { ViewBag.ReturnUrl }))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<h1>Welcome to My Website</h1>
<div>
#Html.TextBoxFor(m => m.UserName, new { placeholder = "Username" })
#Html.PasswordFor(m => m.Password, new { placeholder = "Password" })
<button>Login to MyWebsite</button>
<div>
#Html.CheckBoxFor(m => m.RememberMe)
<label for="keep">Keep me logged in for 5 days</label>
</div>
#Html.RouteLink("Password recovery",
routeValues: new { controller = "Password", action = "Forgot" })
<br />
</div>
}
I should also add that this problem occurs on an instance of the solution which I branched in tfs express 2013. there is an extra level in the directory structure than in the original which works although I could not explain why that matters. the problem is the more vexing because the base code works, while the branched code does not. and I copied the working code into the branch to make sure everything was exactly the same, yet the application is adding this additional element, resource.ashx to the computed url. I also set the directory structure the same, but no success.
As a second addition, to answer rowan's question about routing, this is what the application has. I have inherited it, so I may not be able to answer / justify all questions about decisions made.
public class RouteConfig
{
/// <summary>
/// Registers the routes.
/// </summary>
/// <param name="routes">The routes.</param>
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
////routes.LowercaseUrls = true;
// Client website routes
routes.MapRoute(
"user-activation",
"user/activate/{token}",
new { controller = "user", action = "activate" });
routes.MapRoute(
"password-reset",
"password/reset/{token}",
new { controller = "password", action = "reset" });
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional });
}
}
I figured out the problem. a third party control, which was not even being used or referenced, but which nonetheless was sitting around in the solution, was the cause of the unexpected route which caused the unwanted url on my login page. deleting the related dlls fixed the problem. however, I do need that component, so will have to work out a solution.
special thanks to rowan for getting me on the right path. all I needed to do was inspect the RouteTable in the debugger, and it became obvious what the cause and culprit were. previously I had relied on eyeballing the code, but it was doing something more than I expected. hence the need to inspect the runtime state - not just design time.

MVC: A public method on my controller is called OK in my development server, but not the testing server

I am completely baffled by this.
I have a public method on my controller which works on my development machine. But when I deploy the app I get an error message saying the method is not found;
[HttpGet]
[Authorize(Roles = "Administrator, AdminIT, ManagerIT")]
public ActionResult ListExistingIT(GridSortOptions sort, int? page)
{
if (Request.QueryString["lastPersonMessage"] == null)
ViewData["LastPersonMessage"] = string.Empty;
else
ViewData["LastPersonMessage"] = Request.QueryString["lastPersonMessage"];
EmployeeListViewModel elvm = new EmployeeListViewModel();
elvm.EmployeeList = EmployeeExtended.GetITEmployees();
if (sort.Column != null)
{
elvm.EmployeeList = elvm.EmployeeList.OrderBy(sort.Column, sort.Direction);
}
elvm.EmployeeList = elvm.EmployeeList.AsPagination(page ?? 1, Utility.GetPageLength());
ViewData["sort"] = sort;
return View(elvm);
}
The error message is; System.Web.HttpException: A public action method 'ListExistingIT' was not found on controller 'SHP.Controllers.EmployeeController'.
Now you might think that IIS is not picking up the latest deployment. However I make a change elsewhere and deploy it, and that works. I also restart IIS as well.
I cannot imagine how this happens, or how to detect where the error could be.
There is plenty of discussion on a similar (the same?) issue here on SO:Intermittent asp.net mvc exception: “A public action method ABC could not be found on controller XYZ.”
I can think of 3 different possibilities:
A conflict with the HttpVerb
causing the method not to be found.
A conflict with the filters applied
causing the method to be avoided.
A routing issue, but this one is
probably the last possibility. You
may want to try testing with the
RouteDebugger and see what that
shows you.

Resources