At this moment, I am register at AreaRegistraion as below:-
public class AdminAreaRegistration : AreaRegistration
{
public override string AreaName
{
get { return "Admin"; }
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"custom_admin_order",
"Admin/Order/List/",
new { controller = "CustomOrder", action = "List", area = "Admin", id = "" },
new[] { "Misc.CustomAdminOrder.Controllers" });
}
}
It is working, but sometime doesn't work and need to restart the application and clear cache several times to make it work.
So right now I need a better way to make it 100% work.
Related
How can I set a custom contract resolver in web api configuration? My code is relatively new and has no custom contract resolver till now.
I have added no other customization besides routing.
I tried in three different ways and none worked:
public static void Register(HttpConfiguration config)
{
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
//attempt 1
config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CustomContractResolver();
//attempt 2
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CustomContractResolver();
//attempt 3
JsonConvert.DefaultSettings = () => new JsonSerializerSettings
{
ContractResolver = new CustomContractResolver()
};
}
The custom contract resolver code, breakpoint never reaches here when I'm debugging:
public class CustomContractResolver : CamelCasePropertyNamesContractResolver
{
protected override string ResolvePropertyName(string propertyName)
{
var regex = new Regex(#"([_])(\w)");
if (regex.IsMatch(propertyName))
{
var result = regex.Replace(propertyName.ToLower(), (match) => { return match.Groups[2].Value.ToUpper(); });
return result;
}
else
return base.ResolvePropertyName(propertyName);
}
}
Is there something that is missing?
Edit 1:
I'm using ASP.NET WebApi 5.2.1 AND MVC 5.2.7, JSON.NET (Newtonsoft.Json) v13.0.1 (and already tried the old v12)
My Global Asax is very simple as well:
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register); //<- web api configuration
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes); //<- mvc configuration
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
}
The MVC RouteConfig class:
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.IgnoreRoute("{resource}.ashx/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
Edit 2
Here is some test web api controllers:
using System.Web.Http;
namespace Kronos.Web.Geolocalizacao.Controllers.Api
{
public class TestController : ApiController
{
[HttpGet]
public TestModel Obtain()
{
return new TestModel { CODE_IDENTIFICATION = 1, DEFAULT_DESCRIPTION = "TEST DAT THING" };
}
}
public class TestModel
{
public decimal CODE_IDENTIFICATION { get; set; }
public string DEFAULT_DESCRIPTION { get; set; }
}
}
Used the Tabbed Postman chrome addon to test
Postman tests
Your problem has nothing to do with how you are registering your global settings -- setting config.Formatters.JsonFormatter.SerializerSettings.ContractResolver is correct as per this question. Your problem is that Json.NET does not call ResolvePropertyName() when the contract resolver also has a NamingStrategy -- and your base class CamelCasePropertyNamesContractResolver does indeed have a naming strategy.
This can be verified by checking the current Json.NET reference source for DefaultContractResolver.SetPropertySettingsFromAttributes():
if (namingStrategy != null)
{
property.PropertyName = namingStrategy.GetPropertyName(mappedName, hasSpecifiedName);
}
else
{
property.PropertyName = ResolvePropertyName(mappedName);
}
Broken demo fiddle #1 here.
If I simply modify your CustomContractResolver to inherit from DefaultContractResolver (which has a null NamingStrategy by default), then it works:
public class CustomContractResolver : DefaultContractResolver
{
readonly NamingStrategy baseNamingStrategy = new CamelCaseNamingStrategy();
protected override string ResolvePropertyName(string propertyName)
{
var regex = new Regex(#"([_])(\w)");
if (regex.IsMatch(propertyName))
{
var result = regex.Replace(propertyName.ToLower(), (match) => { return match.Groups[2].Value.ToUpper(); });
return result;
}
else
return baseNamingStrategy.GetPropertyName(propertyName, false);
}
}
Fixed demo fiddle #2 here.
However, a cleaner solution would be to replace your custom contract resolver with a custom naming strategy:
public class CustomNamingStrategy : CamelCaseNamingStrategy
{
public CustomNamingStrategy() : base() { }
public CustomNamingStrategy(bool processDictionaryKeys, bool overrideSpecifiedNames) : base(processDictionaryKeys, overrideSpecifiedNames) { }
public CustomNamingStrategy(bool processDictionaryKeys, bool overrideSpecifiedNames, bool processExtensionDataNames) : base(processDictionaryKeys, overrideSpecifiedNames, processExtensionDataNames) { }
readonly Regex regex = new Regex(#"([_])(\w)");
protected override string ResolvePropertyName(string name)
{
if (regex.IsMatch(name))
{
var result = regex.Replace(name.ToLower(), (match) => { return match.Groups[2].Value.ToUpper(); });
return result;
}
return base.ResolvePropertyName(name);
}
}
And then configure it in settings like so:
settings.ContractResolver = new DefaultContractResolver
{
// Set the constructor parameters as per your preference. These values are consistent with CamelCasePropertyNamesContractResolver
NamingStrategy = new CustomNamingStrategy(processDictionaryKeys: true, overrideSpecifiedNames: true),
};
Demo fiddle #3 here.
I am trying to push a view in xamrian forms from the view model but I cant appear to get it to work its really when the user has entered correct username and password it should show the home page.
You will see I have the on submit command this is just mock data at present so dont mind the design of code at this stage will change.
Usually I would use
var stocktakepage = new StockTake();
await Navigation.PushAsync(stocktakepage);
But the model does not no about the navigation stack in the class is their another way to navigate from the view model thanks.
public class LoginViewModel : INotifyPropertyChanged
{
public Action DisplayInvalidLoginPrompt;
public event PropertyChangedEventHandler PropertyChanged = delegate { };
private string email;
public string Email
{
get { return email; }
set
{
email = value;
PropertyChanged(this, new PropertyChangedEventArgs("Email"));
}
}
private string password;
public string Password
{
get { return password; }
set
{
password = value;
PropertyChanged(this, new PropertyChangedEventArgs("Password"));
}
}
public ICommand SubmitCommand { protected set; get; }
public LoginViewModel()
{
SubmitCommand = new Command(OnSubmit);
}
public void OnSubmit()
{
if (email != "handheld1" || password != "test123")
{
DisplayInvalidLoginPrompt();
}else
{
}
}
}
I found the answer here
https://forums.xamarin.com/discussion/21822/call-navigation-pushasync-from-viewmodel But also on my main login page i have this. What this does is act like a delegate and allows you to push the view from the original calling page.
public Login()
{
var vm = new LoginViewModel();
this.BindingContext = vm;
Password.Completed += (object sender, EventArgs e) =>
{
vm.SubmitCommand.Execute(null);
};
}
You can also use the below in order to Navigate from your ViewModel. You can do this for each type of page you want. Check below examples:
await App.Current.MainPage.Navigation.PushAsync(new PageName());
also
await App.Current.MainPage.Navigation.PushModalAsync(new NavigationPage(new PageName()) { BarBackgroundColor = Color.FromHex("#101010"), BarTextColor = Color.White, }, true);
I just barely created a new Area to organize my code.
But currently I am having trouble actually linking it from my "base" or "root" index page, to my new area page.
#Html.ActionLink("Tube Record Form", "BearingAssemblyForm", "_HiCT", new { area = "HICT" }, null)
public class HICTAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "HICT";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"HICT_default",
"HICT/{controller}/{action}/{id}",
new {controller = "_HiCT", action = "BearingAssemblyForm", id = UrlParameter.Optional }
);
}
}
The resource cannot be found.
And it seems its linked wrongly
Requested URL: /HICT/HiCT/BearingAssemblyForm
Controller: HiCT,
View/Action: BearingAssemblyForm, Area: HICT.
How would I like this?
Thank you so much.
Try this:
#Html.ActionLink("LinkText",
"ActionName",
"ControllerName",
new { area = "HICT" }, null)
I think you're not using the correct #Html.ActionLink method overload.
First off all, see if your area is registered correctly:
public class Routes : AreaRegistration
{
public override string AreaName
{
get
{
return "HICT";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"HICT_default",
"HICT/{controller}/{action}/{id}",
new { controller = "_HiCT", action = "BearingAssemblyForm", id = UrlParameter.Optional }
);
}
Make sure you're calling RegisterAllAreas inside the Global.asax.cs file:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
...
}
/Master/BearingAssemblyForm
usually, Master is the controller and the 2nd part is action, so it seems your controller name is different than your route.
Its been a wile but this should work.
#Html.ActionLink("Tube Record Form", "action", "Area/controller")
Are you calling:
AreaRegistration.RegisterAllAreas();
on Application_Start in your Global.asax? What server are you using for development Cassini, IISExpress, IIS?
Edit after reviewing more detailed information.
In your Admin Area Registration File if you have this code
context.MapRoute(
"Admin_default",
"Admin/{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional },
new string[] { "CoolProject.Web.Areas.Admin.Contollers" }
);
I think there is a typo in CoolProject.Web.Areas.Admin.Contollers and it should be CoolProject.Web.Areas.Admin.Controllers?
I am getting the above when I try and open a view in a controller in an Area. Ninject is set up as follows:
public class NinjectControllerFactory : DefaultControllerFactory
{
private IKernel kernel = new StandardKernel(new RLSBCWebSiteServices());
protected override IController GetControllerInstance(RequestContext context, Type controllerType)
{
if (controllerType == null)
return null;
return (IController)kernel.Get(controllerType);
}
private class MyWebSiteServices : NinjectModule
{
public override void Load()
{
Bind<IMatchesRepository>().To<SqlMatchesRepository>().WithConstructorArgument("connectionString",
ConfigurationManager.ConnectionStrings["MyWebSiteDb"].ConnectionString);
}
}
}
If I place a breakpoint in the code, I see the RequestContext context contains the following values:
context.RouteData.DataTokens.Values[0] = “MyWebSite.WebUI.Areas.Visitor” context.RouteData.DataTokens.Values[1] = “Visitor” which is the Area
context.RouteData.Values.Values[0] = “admin” which is the Controller
context.RouteData.Values.Values[1] = “register” which is the View
However controllerType == null, instead on the controller name.
This transfer to the new page is being triggered by
Html.ActionLink("here", "Register", "Admin", new { area = "Visitor" }, null)
which is on the Login page. However the same thing happens if I enter
http://example.com/Visitor/admin/register
into IE8
The area registration is as follows:
public class VisitorAreaRegistration : AreaRegistration
{
public override string AreaName { get { return "Visitor"; } }
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Visitor_default",
"Visitor/{controller}/{action}/{id}",
new { controller = "Admin", action = "Register", id = UrlParameter.Optional }
);
}
}
Has anyone managed to get Areas working with NinjectControllerFactory, or is there something wrong with my set-up?
Instead of creating your own NinjectControllerFactory use the latest version of Ninject.Web.Mvc. It supports Areas. See: https://github.com/ninject/ninject.web.mvc
Check your controller and action name in view. I also got same error as an action name was wrong.
I have this piece of code:
public class Authenticate : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
{
filterContext.HttpContext.Response.Redirect("/");
}
}
}
I was wondering if it is possible to make it redirect to the view for action="Login" controller="AdminLogin"? And how do I pass some message to the login view that tells "you need to login to access that" or similar?
/M
Here is how I solved the redirect-part:
public class Authenticate : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
{
RedirectToRoute(filterContext,
new
{
controller = "AdminLogin",
action = "AdminLogin"
});
}
}
private void RedirectToRoute(ActionExecutingContext context, object routeValues)
{
var rc = new RequestContext(context.HttpContext, context.RouteData);
string url = RouteTable.Routes.GetVirtualPath(rc,
new RouteValueDictionary(routeValues)).VirtualPath;
context.HttpContext.Response.Redirect(url, true);
}
}
Not sure if it is optimal but seems to do the job correctly