Additional:
Download my project with my failed attempt at converting to AttributeRouting.
The project will run correctly when the message on the home page changes between "No new email." and "You have mail!". In its current errored state that message does not change.
Errors in the javascript console will show.
Navigating directly to /Checkemail with the browser results in 404 error.
Original Post:
This is a question about AttributeRouting (using latest v3.4.1).
I am trying to hook a GET[""] onto the following code.
[GET("")] I get a 404 - resource not found.
[GET("CheckEmail")] I get a 405 - Method not allowed.
I am trying to convert this project to AttributeRouting: source code. The checkemail action is where I am failing.
The method is an asynchronous method as part of an "ajax long polling" technique.
I have the following with my dismal attempts commented:
public class CheckEmailController : AsyncController
{
//
// GET: /CheckEmail/
//tried [GET("")]
//tried [GET("CheckEmail")]
public void IndexAsync()
{
AsyncManager.OutstandingOperations.Increment();
MyAsyncEmailChecker.CheckForEmailAsync(hasEmail =>
{
AsyncManager.Parameters["hasEmail"] = hasEmail;
AsyncManager.OutstandingOperations.Decrement();
});
}
private class IndexResponse
{
public bool d { get; set; }
}
public JsonResult IndexCompleted(bool hasEmail)
{
return this.Json(new IndexResponse() { d = hasEmail });
}
}
Global.asax.cs - as for all my AR projects
public class MvcApplication : System.Web.HttpApplication
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
}
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}
}
thank you
If you are on ASP.NET MVC 4 and .NET 4.5 then you should just use the async keyword and Tasks. This should fix your issue with routing and reduce the complexity in your controllers. Here is the a link to whitepaper by microsoft.
http://www.asp.net/mvc/tutorials/mvc-4/using-asynchronous-methods-in-aspnet-mvc-4
but to sum it up your code would change to this.
public class CheckEmailController : AsyncController
{
//
// GET: /CheckEmail/
[GET("CheckEmail")]
public async Task<ActionResult> Index()
{
return View( new IndexReponse {
d = await MyAsyncEmailChecker.CheckForEmailAsync()
});
}
public class IndexResponse
{
public bool d { get; set; }
}
}
Related
There are lots of link I found for reference. But unfortunately they didn't worked for me. So I am posting here. Issue is my control is not hitting the "OnActionExecuting". This is the first time I am working with WebAPI and I guess I am missing something somewhere. Please HELP!!
My API filter looks like this:
public class ValidateCustomAntiForgeryTokenAttribute : System.Web.Http.Filters.ActionFilterAttribute
{
public new void OnActionExecuted(HttpActionExecutedContext filterContext)
{
//removed for Breviety
}
public void OnActionExecuting(HttpActionExecutedContext request)
{
//removed for Breviety
}
}
I registered my filter on Startup.cs:
public class StartUp : System.Web.HttpApplication
{
public void Configuration(IAppBuilder app)
{
HttpConfiguration config = new HttpConfiguration();
//removed for Breveity
config.Filters.Add(new ValidateCustomAntiForgeryTokenAttribute());
}
}
And using it on one of my controller:
[CustomAuthorize]
[ValidateCustomAntiForgeryToken]
public class QuestionController : ApiController
{
}
public void OnActionExecuting(HttpActionContext request)
{
//removed for Breviety
}
OnActionExecuting expects parameter HttpActionContext
Using MVC
Naturally, after authentication in a Web API, I want to assign session("LoggedIn") the value True.
But the session in my Web API keeps returning NullReference.
Any workaround?
Thanks.
WebApiConfig.cs
public static class WebApiConfig
{
public static string UrlPrefix { get { return "api"; } }
public static string UrlPrefixRelative { get { return "~/api"; } }
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: WebApiConfig.UrlPrefix + "/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
Global.asax.cs
public class MvcApplication : System.Web.HttpApplication
{
...
protected void Application_PostAuthorizeRequest()
{
if (IsWebApiRequest())
{
HttpContext.Current.SetSessionStateBehavior(SessionStateBehavior.Required);
}
}
private bool IsWebApiRequest()
{
return HttpContext.Current.Request.AppRelativeCurrentExecutionFilePath.StartsWith(WebApiConfig.UrlPrefixRelative);
}
}
for more details Accessing Session Using ASP.NET Web API
You need to Sets the type of session state behavior that is required in order to support an HTTP request.
You can do the changes in Application_PostAuthorizeRequest() in Global.asax file.
using System.Web.Http;
using System.Web;
using System.Web.SessionState;
namespace Sample
{
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
WebApiConfig.Register(GlobalConfiguration.Configuration);
}
protected void Application_PostAuthorizeRequest()
{
HttpContext.Current.SetSessionStateBehavior(SessionStateBehavior.Required);
}
}
}
I know we could simply use an app_offline.htm file to do this.
But I want to be able access the website if my IP is 1.2.3.4 (for example), so that I can do a final testing.
if( IpAddress != "1.2.3.4" )
{
return Redirect( offlinePageUrl );
}
How can we implement this in ASP.NET MVC 3?
You can use a catch-all route with a RouteConstraint with the IP check:
Make sure you put the offline route first.
routes.MapRoute("Offline", "{controller}/{action}/{id}",
new
{
action = "Offline",
controller = "Home",
id = UrlParameter.Optional
},
new { constraint = new OfflineRouteConstraint() });
and the constraint code:
public class OfflineRouteConstraint : IRouteConstraint
{
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
// return IpAddress != "1.2.3.4";
}
}
Per Max's suggestion here is an actual implementation.
public class MvcApplication : System.Web.HttpApplication
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new CheckForDownPage());
}
//the rest of your global asax
//....
}
public sealed class CheckForDownPage : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var path = System.Web.Hosting.HostingEnvironment.MapPath("~/Down.htm");
if (System.IO.File.Exists(path) && IpAddress != "1.2.3.4")
{
filterContext.HttpContext.Response.Clear();
filterContext.HttpContext.Response.Redirect("~/Down.htm");
return;
}
base.OnActionExecuting(filterContext);
}
}
You can define a global filter that stop all the requests if they don't come from your IP. you can enable the filter by configuration.
I got an infinite loop on colemn615's solution, so I added a check for the offline page.
Also, for later versions of ASP.NET this is split into a FilterConfig.cs file in the App_Start folder.
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new CheckForDownPage());
}
public sealed class CheckForDownPage : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (HttpContext.Current.Request.RawUrl.Contains("Down.htm"))
{
return;
}
var path = System.Web.Hosting.HostingEnvironment.MapPath("~/Down.htm");
if (System.IO.File.Exists(path) && IpAddress != "1.2.3.4")
{
filterContext.HttpContext.Response.Clear();
filterContext.HttpContext.Response.Redirect("~/Down.htm");
return;
}
base.OnActionExecuting(filterContext);
}
}
I add an AppSetting in the Web.Config file:
<add key="MaintenanceMsg" value="We are currently performing some routine maintenance. We expect to be back up at around 01:00." />
I then update the global.asax file's Application_BeginRequest method to check if the appsetting has a value, if it does, I redirect everything to the maintenance page:
private void Application_BeginRequest(object sender, EventArgs e)
{
if(!string.IsNullOrWhiteSpace(ConfigurationManager.AppSettings["MaintenanceMsg"]) && !Request.Url.ToString().Contains("UndergoingMaintenance"))
Response.Redirect("~/Home/UndergoingMaintenance");
** Do whatever you do when you don't want to show your maintenance page here**
}
Finally, create your view and controller action.
If you use Azure you can simply add and delete the value for the AppSetting in the portal so you can suspend your site in a matter of minutes without a deployment.
I am upgrading a web app from ASP.NET 3 Preview 1 to the RTM and I am confused by the updated approach to dependency injection. I am using StructureMap for this but that's not really relevant to my question. Previously all I needed to do was as follows:
x.For<IControllerFactory>().Use<DefaultControllerFactory>();
x.For<IServiceLocator>().Use(MvcServiceLocator.Current);
Now it seems like I need to provide implementations of IControllerActivator, IViewPageActivator and ModelMetadataProvider because otherwise I get an error from StructureMap because MVC tries to locate them using the dependency resolver. From a look at the MVC source there do not seem to be public default implementations. Am I missing something in setting these up? Surely these should be configured by convention?
Examples of what needs configuring and how with StructureMap would be appreciated. For reference I am currently using the following ugly kludge which forces MVC to use its internal defaults:
x.For<IControllerFactory>().Use<DefaultControllerFactory>();
x.For<IDependencyResolver>().Use(() => DependencyResolver.Current);
x.For<IControllerActivator>().Use(() => null);
x.For<IViewPageActivator>().Use(() => null);
x.For<ModelMetadataProvider>().Use(ModelMetadataProviders.Current);
EDIT: Just to be clear I have a working StructureMap implementation of the Dependency Resolver - the issue is why MVC is complaining about all these interfaces not being configured in the container.
I was able to get StructureMap to work with ASP.NET MVC3 by creating a Dependency Resolver(IDependencyResolver) class, then registering that class in the global.asax. I have not fully tested this code. But, it has been working without any issues in two applications.
StructureMapDependencyResolver.cs
using System.Linq;
using System.Web.Mvc;
using StructureMap;
namespace SomeNameSpace
{
public class StructureMapDependencyResolver : IDependencyResolver
{
private readonly IContainer container;
public StructureMapDependencyResolver(IContainer container)
{
this.container = container;
}
public object GetService(System.Type serviceType)
{
try
{
return this.container.GetInstance(serviceType);
}
catch
{
return null;
}
}
public System.Collections.Generic.IEnumerable<object> GetServices(System.Type serviceType)
{
return this.container.GetAllInstances<object>()
.Where(s => s.GetType() == serviceType);
}
}
}
Global.asax.cs
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
}
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
DependencyResolver.SetResolver(new StructureMapDependencyResolver(InitContainer()));
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}
private static IContainer InitContainer()
{
ObjectFactory.Initialize(x =>
{
x.Scan(y =>
{
y.WithDefaultConventions();
y.AssembliesFromApplicationBaseDirectory();
y.LookForRegistries();
});
});
return ObjectFactory.Container;
}
I've figured this out thanks to the link #Michael Carman posted in a comment on his answer. I'm not sure of the etiquette here as to whether that warrants accepting his actual answer as it wasn't quite right (I've given him +1 vote) but I thought I'd post my own answer to explain exactly what the issue was.
The problem was down to a combination of my implementation of IDependencyResolver and my container configuration. Originally I had:
public class StructureMapDependencyResolver : IDependencyResolver
{
public object GetService(Type serviceType)
{
return ObjectFactory.GetInstance(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
foreach (object obj in ObjectFactory.GetAllInstances(serviceType))
{
yield return obj;
}
}
}
but I have now changed to this based on Steve Smith's blog post linked to in Jeremy Miller's blog post:
public class StructureMapDependencyResolver : IDependencyResolver
{
public object GetService(Type serviceType)
{
if (serviceType.IsAbstract || serviceType.IsInterface)
{
return ObjectFactory.TryGetInstance(serviceType);
}
else
{
return ObjectFactory.GetInstance(serviceType);
}
}
public IEnumerable<object> GetServices(Type serviceType)
{
foreach (object obj in ObjectFactory.GetAllInstances(serviceType))
{
yield return obj;
}
}
}
on its own this still doesn't resolve the issue until I remove this configuration expression:
x.For<IControllerFactory>().Use<DefaultControllerFactory>();
According to the documentation TryGetInstance only returns types registered with the container and will return null if none exist. I presume the MVC 3 code relies on this behaviour to indicate that it should use its defaults, hence in my original case I had to register these defaults with my container. Tricky one!
This works for me for both MVC and Web API..
namespace Web.Utilities.DependencyResolvers
{
public class StructureMapResolver : IServiceLocator, IDependencyResolver
{
private readonly IContainer _container;
public StructureMapResolver(IContainer container)
{
if (container == null)
throw new ArgumentNullException("container");
this._container = container;
}
public IDependencyScope BeginScope()
{
return new StructureMapResolver(this._container.GetNestedContainer());
}
public object GetInstance(Type serviceType, string instanceKey)
{
if (string.IsNullOrEmpty(instanceKey))
{
return GetInstance(serviceType);
}
return this._container.GetInstance(serviceType, instanceKey);
}
public T GetInstance<T>()
{
return this._container.GetInstance<T>();
}
public object GetService(Type serviceType)
{
return GetInstance(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
return this._container.GetAllInstances(serviceType).Cast<object>();
}
public T GetInstance<T>(string instanceKey)
{
return this._container.GetInstance<T>(instanceKey);
}
public object GetInstance(Type serviceType)
{
return serviceType.IsAbstract || serviceType.IsInterface ?
this._container.TryGetInstance(serviceType) : this._container.GetInstance(serviceType);
}
public IEnumerable<T> GetAllInstances<T>()
{
return this._container.GetAllInstances<T>();
}
public IEnumerable<object> GetAllInstances(Type serviceType)
{
return this._container.GetAllInstances(serviceType).Cast<object>();
}
public void Dispose()
{
this._container.Dispose();
}
}
}
Edit
Orignal Title: My transaction is closed by the time it gets to my Repo. What am I doing wrong?
I got a answer to my origanl questions(I forgot to open the transaction lol). Now I am wondering if my code is automatically closing the session or if I have to somehow tell it to do this.
Hi
I am using mvc 3.0, nhibernate, fluent nhibernate and ninject 2.0
Global.asax
// Note: For instructions on enabling IIS6 or IIS7 classic mode,
// visit http://go.microsoft.com/?LinkId=9394801
public class MvcApplication : System.Web.HttpApplication
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
}
protected void Application_Start()
{
// Hook our DI stuff when application starts
SetupDependencyInjection();
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}
public void SetupDependencyInjection()
{
// Tell ASP.NET MVC 3 to use our Ninject DI Container
DependencyResolver.SetResolver(new NinjectDependencyResolver(CreateKernel()));
}
protected IKernel CreateKernel()
{
var modules = new INinjectModule[]
{
new NhibernateModule(),
new ServiceModule(),
new RepoModule()
};
return new StandardKernel(modules);
}
}
Session Factory
public class NhibernateSessionFactory
{
public ISessionFactory GetSessionFactory()
{
ISessionFactory fluentConfiguration = Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2008.ConnectionString(c => c.FromConnectionStringWithKey("test")))
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<MyMaps>())
.BuildSessionFactory();
return fluentConfiguration;
}
}
Session Factory Provider
public class NhibernateSessionFactoryProvider : Provider<ISessionFactory>
{
protected override ISessionFactory CreateInstance(IContext context)
{
var sessionFactory = new NhibernateSessionFactory();
return sessionFactory.GetSessionFactory();
}
}
Nhibernate Module
public class NhibernateModule : NinjectModule
{
public override void Load()
{
Bind<ISessionFactory>().ToProvider<NhibernateSessionFactoryProvider>().InSingletonScope();
Bind<ISession>().ToMethod(context => context.Kernel.Get<ISessionFactory>().OpenSession()).InRequestScope();
}
}
Service Module
public class ServiceModule : NinjectModule
{
public override void Load()
{
Bind<ITest>().To<Test>();
}
}
Repo Module
public class RepoModule : NinjectModule
{
public override void Load()
{
Bind<IStudentRepo>().To<StudentRepo>();
}
}
HomeController
private readonly ITest test;
public HomeController(ITest test)
{
this.test = test;
}
//
// GET: /Home/
public ActionResult Index()
{
return View();
}
Test(my service layer file)
public class Test : ITest
{
private readonly IStudentRepo studentRepo;
public Test(IStudentRepo studentRepo)
{
this.studentRepo = studentRepo;
}
}
Repo
public class StudentRepo : IStudentRepo
{
private readonly ISession session;
public StudentRepo(ISession session)
{
this.session = session;
}
}
When I look through my debugger at the session that is coming into my repo. It says the session is open and connected but the (session.Transaction).IsActive = false
You're currently set up to use implicit transactions, which I don't believe are exposed through session.Transaction. Of course, Use of implicit transactions is discouraged.