I have a problem with my MVC3 web application. I am getting an RuntimeBinderException.
There is a problem with my dynamic page metatags. Meta tags are set from .resx files. I think it can't access the resources at runtime. And also people in other countries can't access the website. There is a connection time-out error. But we are in USA and we can access the website. Do you have any idea?
My metatags is below;
public ActionResult Index()
{
ViewBag.Description = Glob.HomeDescription;
ViewBag.Keywords = Glob.HomeKeywords; ;
ViewBag.Title = Glob.HomeTitle;
var data = new HomeData();
data.AnnouncementLists = _announcementService.GetAnnouncementList(LanguageId).Data;
data.FeedBackLists = _feedbackService.GetFeedbackListHome(LanguageId).Data;
data.Newfeedback = new FeedBackDTO { Context = "", Id = Guid.NewGuid(), Date = DateTime.Now, FeedBackId = Guid.NewGuid(), LanguageId = LanguageId, Status = false, LanguageName = "", Who = "" };
return View(data);
}
The error is below;
Exception Type: Microsoft.CSharp.RuntimeBinder.RuntimeBinderException
Message: 'System.Dynamic.DynamicObject' does not contain a definition for 'Description'
Stack Trace: at Microsoft.CSharp.RuntimeBinder.RuntimeBinderController.SubmitError(CError pError) at Microsoft.CSharp.RuntimeBinder.Semantics.LangCompiler.SubmitError(CParameterizedError error) at Microsoft.CSharp.RuntimeBinder.Semantics.MemberLookup.ReportErrors() at Microsoft.CSharp.RuntimeBinder.RuntimeBinder.BindProperty(DynamicMetaObjectBinder payload, ArgumentObject argument, LocalVariableSymbol local, EXPR optionalIndexerArguments, Boolean fEventsPermitted) at Microsoft.CSharp.RuntimeBinder.RuntimeBinder.BindAssignment(DynamicMetaObjectBinder payload, ArgumentObject[] arguments, Dictionary`2 dictionary) at Microsoft.CSharp.RuntimeBinder.RuntimeBinder.DispatchPayload(DynamicMetaObjectBinder payload, ArgumentObject[] arguments, Dictionary`2 dictionary) at Microsoft.CSharp.RuntimeBinder.RuntimeBinder.BindCore(DynamicMetaObjectBinder payload, IEnumerable`1 parameters, DynamicMetaObject[] args, DynamicMetaObject& deferredBinding) at Microsoft.CSharp.RuntimeBinder.RuntimeBinder.Bind(DynamicMetaObjectBinder payload, IEnumerable`1 parameters, DynamicMetaObject[] args, DynamicMetaObject& deferredBinding) at Microsoft.CSharp.RuntimeBinder.BinderHelper.Bind(DynamicMetaObjectBinder action, RuntimeBinder binder, IEnumerable`1 args, IEnumerable`1 arginfos, DynamicMetaObject onBindingError)**strong text**
Any advice would be helpful. Thanks.
Related
I have a problem about MVC WebAPi. Here some information from my project.
WebApiConfig;
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}/{no}",
defaults: new { id = RouteParameter.Optional, no = RouteParameter.Optional }
TapuZeminApiController;
// GET api/<controller>
[Route("api/TapuZeminApi/GetZemins")]
[HttpPost]
public string GetZeminsFromZeminArg(object arg)
{
ZeminArg zemArg = SConvert.DeserializeJSON<ZeminArg>(arg.ToString());
List<TapuZeminModel> zeminList = TapuModule.GetZeminListFromArgs(zemArg);
string jsonResult = SConvert.SerializeJSON(zeminList);
return jsonResult;
}
// GET api/<controller>/5
public string GetZeminsFromTcNo(int id)
{
List<TapuZeminModel> zeminList = TapuModule.GetZeminListFromTcNo(id.ToString());
string jsonResult = SConvert.SerializeJSON(zeminList);
return jsonResult;
}
And i have another a lot of Api like;
TapuParselApiController;
public List<string> GetAdaNo(int id)
{
List<string> adaList = TapuModule.GetAdaListFromMahalleTapuKod(id);
adaList = adaList.OrderBy(x => x, new AlphanumComparator()).ToList();
return adaList;
}
[Route("Api/TapuParselApi/GetParselNo/MahalleId/{id}/AdaNo/{adaNo}")]
public object GetParselNo(int id, string adaNo)
{
List<TapuParselModel> parselList = TapuModule.GetParselListFromMahalleAndAdaTapuKod(id, adaNo);
List<string> parselNoList = parselList.Select(x => x.ParselNo).ToList<string>();
parselNoList = parselNoList.OrderBy(x => x, new AlphanumComparator()).ToList();
var jsonResult = SConvert.SerializeJSON(parselNoList);
return jsonResult;
}
I can use all of api but one of them not working. When i tried to reach
http://localhost:55591/Api/TapuZeminApi/GetZeminsFromTcNo/41206410132
it returns
This XML file does not appear to have any style information associated with it. The document tree is shown below.
The request is invalid.
<MessageDetail>
The parameters dictionary contains a null entry for parameter 'id' of non-nullable type 'System.Int32' for method 'System.String GetZeminsFromTcNo(Int32)' in 'Sehir.Catalog.Areas.Tapu.Controllers.TapuZeminApiController'. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter.
</MessageDetail>
</Error>
Why is getting this error?? What should i do?
http://localhost:55591/Api/TapuZeminApi/GetZeminsFromTcNo/41206410132
The value 41206410132 in this http request is too large for an int.
You need to change the parameter type in your controller action to a long.
// GET api/<controller>/5
public string GetZeminsFromTcNo(long id)
{
List<TapuZeminModel> zeminList = TapuModule.GetZeminListFromTcNo(id.ToString());
string jsonResult = SConvert.SerializeJSON(zeminList);
return jsonResult;
}
You can read more about the limits of numeric types here.
I am not allowed to install fiddler at work so I am kind of flying blind.
I am running the web api and the web executable on local host through two separate instances of visual studio
I am fairly certain my Web API is working ok I type the URL manually into a web browser it asks me for user Id and password and then returns my JSON.
The web executable that calls the web api also works fine until I attempted to add BASIC authentication to the controller method now I am receiving a 401 error.
here is my code from the executable.
Public Function get_vsmric_webApi(ByRef sErrorDescription As String) As Boolean
Try
Using proxy As New WebClient()
Dim myurl As String = ConfigurationManager.AppSettings("WEBAPI_URL") & "vsmric"
Dim userName As String = "QBERT"
Dim passWord As String = "Qb3RT!"
Dim credentials As String = Convert.ToBase64String(Encoding.ASCII.GetBytes(userName + ":" + passWord))
proxy.Headers(HttpRequestHeader.Authorization) = "BASIC" + credentials
Dim json As String = proxy.DownloadString(myurl)
Dim rics As List(Of DB2VSMRIC) = JsonConvert.DeserializeObject(Of List(Of DB2VSMRIC))(json)
Dim list As List(Of DB2VSMRIC) = rics.Where(Function(p) HasData(p.Cage)).ToList
If list.Count < 1 Then
sErrorDescription = "No VSMRIC w/Cage records found."
Else
dictShipFrom = New Dictionary(Of String, String)
dictShipFrom = list.ToDictionary(Function(p) p.Ric, Function(p) p.Dodaac)
dictCage = New Dictionary(Of String, String)
dictCage = list.ToDictionary(Function(p) p.Ric, Function(p) p.Cage)
End If
End Using
Catch ex As Exception
sErrorDescription = "Exception in get_vsmric_webApi(), " & ex.Message
Return False
Finally
End Try
Return True
End Function
here is the controller method on the web api
[CustomAuthentication]
[CustomAuthorization("qbert")]
public class VSMRICController : ApiController
{
/// <summary>
/// Returns all records in the DB2 VSM RIC table
/// </summary>
/// <param name="id">The ID of the data.</param>
public IEnumerable<DB2VSMRIC> Get()
{
return DB2VSMRICRepository.getAll();
}
here is the filter (for authentication)
public class CustomAuthenticationAttribute : Attribute, IAuthenticationFilter
{
// the job of the AuthenticateAsync method is to examine the request to see whether it contains
// the information that is required to identify a user. Information about the request is provided
// through an instance of the HttpAuthenticationContext class.
public Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken)
{
context.Principal = null;
AuthenticationHeaderValue authentication = context.Request.Headers.Authorization;
if (authentication != null && authentication.Scheme == "Basic")
{
string[] authData = Encoding.ASCII.GetString(Convert.FromBase64String(
authentication.Parameter)).Split(':');
context.Principal
= ApiManager.AuthenticateUser(authData[0], authData[1]);
}
if (context.Principal == null)
{
context.ErrorResult
= new UnauthorizedResult(new AuthenticationHeaderValue[]{
new AuthenticationHeaderValue("Basic")}, context.Request);
}
return Task.FromResult<object>(null);
}
public Task ChallengeAsync(HttpAuthenticationChallengeContext context, CancellationToken cancellationToken)
{
return Task.FromResult<object>(null);
}
public bool AllowMultiple
{
get { return false; }
}
}
Again I'm fairly confident the Web API is working fine as I can get to JSON by directly navigating to the url and providing credentials in any web browser. I'm thinking I am doing something wrong when I set up the header in the executable. any thoughts? (I am running everything locally via 2 instance of visual studio)
The problem is on the line where you set the basic authentication. It should be
... = "Basic " + credentials
instead of
... = "BASIC" + credentials
Case sensitive and a space.
Happy coding.
I have created my own extension as:
public static MvcHtmlString hSearch(this HtmlHelper helper, string labelName, string labelCaption, string textName, string textValue, string tableName, string buttonId,
string actionName, string controllerName, object routeValues, object htmlAttributes)
{
var textbuilder = new TagBuilder("input");
textbuilder.MergeAttribute("id", textName);
textbuilder.MergeAttribute("name", textName);
textbuilder.MergeAttribute("value", textValue);
textbuilder.MergeAttributes(new RouteValueDictionary(htmlAttributes));
ModelMetadata metadata = ModelMetadata.FromStringExpression(labelName, helper.ViewData);
String innerText = labelCaption ?? (metadata.DisplayName ?? (metadata.PropertyName ?? labelName.Split('.').Last()));
if (String.IsNullOrEmpty(innerText))
{
return MvcHtmlString.Empty;
}
TagBuilder labelbuilder = new TagBuilder("label");
labelbuilder.Attributes.Add("for", TagBuilder.CreateSanitizedId(helper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(labelName)));
labelbuilder.MergeAttributes(new RouteValueDictionary(htmlAttributes));
labelbuilder.SetInnerText(innerText);
//return new MvcHtmlString(textbuilder.ToString());
var buttonBuilder = new TagBuilder("button");
buttonBuilder.MergeAttribute("id", buttonId);
buttonBuilder.SetInnerText(buttonId);
var formBuilder = new TagBuilder("form");
var urlHelper = new UrlHelper(helper.ViewContext.RequestContext);
formBuilder.Attributes.Add("action", urlHelper.Action(actionName, controllerName, routeValues));
formBuilder.Attributes.Add("method", "Post");
formBuilder.MergeAttributes(new RouteValueDictionary(htmlAttributes));
formBuilder.InnerHtml = labelbuilder.ToString() + textbuilder.ToString() + buttonBuilder.ToString();
return new MvcHtmlString(formBuilder.ToString());
}
I used the extensions in view as:
#Html.hSearch("lblSrch", "Company", "companyName", (string)TempData["cName"], "CHComp", "Search", "Fetch", "Home", null, null)
Now I want to pass tableName when I click the button to the controller.. my controller looks like this:
public ActionResult Fetch(string search, string tablename)
{
var c = cbo.fetchData(search, tablename);
return PartialView(c.ToList());
}
Waiting for reply.. Thanks..
You haven't given us the code for your helper, but at a guess it writes out a label, a text field (textName), and a button. If this is the case, it will post / get companyName=someValue via HTTP back to your controller.
You would typically need to add a FormCollection to your controller if the fields are dynamically sent from the view. Alternatively, why not keep the name of the text search input static, e.g. name="search", which will bind to your controller's parameter of the same name.
Edit
You can pass tableName back to the controller in a hidden field (<input type='hidden' name='tableName' value='{tableNameGoesHere}')
But as per above, your search string will have different names- the model binder isn't going to recognise it as string search.
In my project I'm trying to create an URL in a view inside an area.
The code is this:
#Html.ActionLink("Cancel", MVC.MyArea.MyController.Index(), new { #class = "btn" })
When I view the result in the browser, the generated code is the following:
<a class="btn" href="/MyArea/MyController/MyCurrentAction?Count=3&Keys=System.Collections.Generic.Dictionary%602%2BKeyCollection%5BSystem.String%2CSystem.Object%5D&Values=System.Collections.Generic.Dictionary%602%2BValueCollection%5BSystem.String%2CSystem.Object%5D">Cancel</a>
I went looking for the code in T4MVC and found that this was the method generating the code above (inside the T4Extensions class):
public static MvcHtmlString ActionLink(this HtmlHelper htmlHelper, string linkText, ActionResult result, object htmlAttributes, string protocol = null, string hostName = null, string fragment = null) {
return htmlHelper.RouteLink(linkText, null, protocol, hostName, fragment, result.GetRouteValueDictionary(), htmlAttributes);
}
Apparently, the RouteLink method is not being able to use the result.GetRouteValueDictionary() as it should.
So, I checked the ASP.NET MVC source code and tried to replicate the same functionality. I've changed my T4MVC to this:
public static MvcHtmlString ActionLink(this HtmlHelper htmlHelper, string linkText, ActionResult result, object htmlAttributes, string protocol = null, string hostName = null, string fragment = null) {
var t4mvcResult = result.GetT4MVCResult();
var actionName = t4mvcResult.Action;
var controllerName = t4mvcResult.Controller;
var routeValues = new RouteValueDictionary(t4mvcResult.RouteValueDictionary);
var htmlAttribs = new RouteValueDictionary(htmlAttributes);
return new MvcHtmlString(HtmlHelper.GenerateLink(htmlHelper.ViewContext.RequestContext, htmlHelper.RouteCollection, linkText, null /* routeName */, actionName, controllerName, protocol, hostName, fragment, routeValues, htmlAttribs));
}
Now it's working (which is great, of course), at least for the tests I've made, but I'm afraid that I'm doing something wrong in the first place and that this path can lead me into some problems ahead.
Darn, this looks like a regression in 2.6.69. Can you try 2.6.68 to verify that indeed it worked before? I have hidden 2.6.69 for now so others don't get it automatically in new projects (and when updating).
This was the bug that triggered the bad fix: http://mvccontrib.codeplex.com/workitem/7191
Also, could you try the exact fix mentioned in the last comment in that bug? Change the method to:
public static MvcHtmlString ActionLink(this HtmlHelper htmlHelper, string linkText, ActionResult result, object htmlAttributes, string protocol = null, string hostName = null, string fragment = null)
{
return htmlHelper.RouteLink(linkText, null, protocol, hostName, fragment, result.GetRouteValueDictionary(), HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
}
Sorry about the break!
I am working on a form that is generated dynamically based on some meta-data tables in my database. I create input tags with names like setting_1, setting_53, setting_22 where the number is the primary key of the meta-data. Since the content is dynamic, I am using FormCollection as the sole parameter on POST requests.
Question 1: Is there a FormCollection-like class for GET requests? I want direct access to the query parameters.
Question 2: If I need to pass these query parameters around, is there an easy/safe way to build my URLs?
One of my big concerns is that some of the settings are populated via OAuth, so the user will be redirected to an external page. I will have to pass the query string as "state" which I will need to recover once the user returns. I will need to use this state to pick up where the user left off in the form entry process. All the more reason why I need a very fool-proof mechanism for passing query parameters around.
Has anyone dealt with dynamic pages like these? Are there good patterns and practices for passing these pages around?
Well, you can certainly look at Request.QueryString inside of a controller action.
But if it were me doing it, I'd write a custom model binder instead.
Here's a sample model binder. I haven't tested this!
public class MyModelBinder: DefaultModelBinder
{
private static void BindSettingProperty(
ControllerContext controllerContext,
ModelBindingContext bindingContext,
PropertyDescriptor propertyDescriptor)
{
if (propertyDescriptor.PropertyType != typeof(IDictionary<string, string>))
{
throw new InvalidOperationException("This binder is for setting dictionaries only.");
}
var originalValue = propertyDescriptor.GetValue(bindingContext.Model) as IDictionary<string, string>;
var value = originalValue ?? new Dictionary<string, string>();
var settingKeys = controllerContext.HttpContext.Request.QueryString.AllKeys.Where(k => k.StartsWith("setting_", StringComparison.OrdinalIgnoreCase));
foreach (var settingKey in settingKeys)
{
var key = settingKey.Substring(8);
value.Add(key, bindingContext.ValueProvider.GetValue(settingKey).AttemptedValue);
}
if (value.Any() && (originalValue == null))
{
propertyDescriptor.SetValue(bindingContext.Model, value);
}
}
protected override void BindProperty(
ControllerContext controllerContext,
ModelBindingContext bindingContext,
PropertyDescriptor propertyDescriptor)
{
if (propertyDescriptor.Name.StartsWith("setting_", StringComparison.OrdinalIgnoreCase)
{
BindSettingProperty(controllerContext, bindingContext, propertyDescriptor);
}
else
{
base.BindProperty(controllerContext, bindingContext, propertyDescriptor);
}
}
}