Stop Async call in Global.aspx - c#

i have two mvc applications in one solution.
now i need to maintain session when user redirects from one application to another.
so what my logic is,
passed GUID in URL.
get GUID in another projects Global.asax file using Init() method.
Log in another user.
i done whole code, added below.
now, i am getting call in Init() method but it also calls other methods which are passed in URl.
i.e. call becomes asynch, so because of that, user redirected to other page.
do i need to change my logic or just code?
below is my Global.asax file code.
public override void Init()
{
var userId = Guid.Parse(Request["UserGUID"].ToString());
if (userId != null && userId == Guid.Parse("1B541D9A-AC3E-466F-897B-6F9033F4533C"))
//my logic of login management
}

After more then 8 hours of R&D, i found solution that really helped me.
Actually my way is proper but the method is not right.
Application_AcquireRequestState
is the proper method for my scenario.
my code is :
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
public void Application_AcquireRequestState(object sender, EventArgs e)
{
var userId = HttpContext.Current.Request["UserGUID"];
if (userId != null)
{
Session["UserGuid"] = Guid.Parse(userId.ToString());
//My logic for session handling..
}
}
}

Related

Entry point of WebAPI every time it is accessed

I want to identify the one point which is hit every time before a request goes to the controller in the webAPI. I need to put in a custom authentication at that point. I am already doing a customAuthorization but I want to tweak in some custom authentication even before it reaches the controller.
The application_Start method only gets triggered once and so I am not quite sure what is the one place where the control goes every time we put in a URL in the browser and hit enter.
Gloabal.asax has more methods, which can be overloaded and one of them is Application_BeginRequest
And here's more detailed lifecycle. Controller factory also might help you intercepting and tweeking requests.
protected void Application_BeginRequest(object sender, EventArgs e) //Not triggered with PUT
{
//your code
}
You can opt for ActionFilterAttribute of Web API. This is triggered for every request that comes in.
Execution pipeline:
Controller Constructor > ActionFilter's OnActionExecuting > Controller action > ActionFilter's OnActionExecuted
Simple ActionFilterAttribute implementation:
public class YourFilterName : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
// pre-processing
//Your authentication logic goes here - use actionContext
}
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
var objectContent = actionExecutedContext.Response.Content as ObjectContent;
if (objectContent != null)
{
var type = objectContent.ObjectType; //type of the returned object
var value = objectContent.Value; //holding the returned value
}
Debug.WriteLine("OnActionExecuted Response " + actionExecutedContext.Response.StatusCode.ToString());
}
}

Response Redirect Using In MVC

I want to create connection between global.asax and my controller. We are using a database in our website. We have a code to check whether the database exists or not. If it doesn't not exist, we want to display a message like "database initializing" etc..
Database check in GLOBAL.ASAX :
public class MvcApplication : System.Web.HttpApplication
{
public static bool flag;
protected void Application_Start()
{
Database.SetInitializer<PhoneDexContext>(null);
var connString = ConfigurationManager.ConnectionStrings["DatabaseConnection"].ConnectionString;
using (PhoneDexContext db = new PhoneDexContext())
{
if (!db.Database.Exists())
{
flag = true;
db.Database.CreateIfNotExists();
}
}
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
protected void Application_BeginRequest()
{
if (flag)
{
Response.Redirect("Loading/LoadingScreen");
}
}
}
But we have a problem with using response redirect. It returns
{"Response is not available in this context."}.
We have a controller which is LoadingController and it has this code;
public class LoadingController : Controller
{
// GET: Loading
public ActionResult LoadingScreen()
{
return View();
}
}
But we can't jump to this part. How can i make connection?? Thanks
First, Application_Start does not handle any user requests. It is just perform some start up initialization. It invoked only once when app starts. To do some checks based on user's actions and properly respond you need to move these checks into Application_BeginRequest method.
Second, you also need to check if user already requesting /Loading/LoadScreen before responding with redirect to that page. Otherwise you will get an infinite redirects until database created.
public class MvcApplication : HttpApplication
{
private static bool dbInitialized;
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
// We can do it asynchronously to not block other initialization code.
Task.Run((Action)CreateDataBase);
}
private static void CreateDataBase()
{
Database.SetInitializer<PhoneDexContext>(null);
using (PhoneDexContext db = new PhoneDexContext())
{
if (!db.Database.Exists())
db.Database.CreateIfNotExists();
}
dbInitialized = true;
}
protected void Application_BeginRequest()
{
if (!dbInitialized && !this.Request.Url.LocalPath.StartsWith("/Loading/LoadingScreen", StringComparison.OrdinalIgnoreCase))
{
this.Response.Redirect("/Loading/LoadingScreen");
}
}
}
You can to further and move checks into the ActionFilter as you will able to work with RouteData and check action and controller parameters instead of url. Combined with nameof that would be less error-prone to route changes, renaming, refactoring and so on.
I think this answer will give you what you want: Return different views in a controller
In your case instead of the response.redirect use return View("/Loading/LoadScreen"); ...or something simular
try this
HttpContext.Current.Response.Redirect("/Loading/LoadScreen");
beacuse Response object is not avaliable in application_start method of global.asax.
you must use HttpContext.Current for any situation.
You can also use the 'Auto-Start feature' (How to warm up an ASP.NET MVC application on IIS 7.5? : Darins answer). This will execute once, before the website is ready to serve requests. The downside is you can't show the user a 'please wait' window. Personally I would not check at every request if the database is existent or not. Just execute it; the database update should not take very long I guess?
Application_Start happens before ASP.Net starts processing the request.
You could set a global static flag to indicate the error condition, then handle Application_BeginRequest and check the flag and redirect.
static bool _isDbLoaded;
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start(){
Database.SetInitializer<PhoneDexContext>(null);
var connString = ConfigurationManager.ConnectionStrings["DatabaseConnection"].ConnectionString;
using (PhoneDexContext db = new PhoneDexContext())
{
if (!db.Database.Exists())
{
_isDbLoaded = false;
db.Database.CreateIfNotExists();
}
}
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
}
protected void Application_BeginRequest(){
if(!_isDbLoaded){
Response.Redirect("Loading/LoadingPage");
}
}
Since Request and Response won't be available in your Application_Start event, You might consider having this code somewhere in the MVC request-response pipeline. An action filter is a good place.
public class VerifySetupIsGood : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
var dbSetDate = context.HttpContext.Application["DbSetDate"] as string;
if (String.IsNullOrEmpty(dbSetDate))
{
//to do : Execute your custom code to check db existence here
var values = new Dictionary<string, string> { { "action", "LoadScreen" },
{ "controller", "Loading" } };
var r = new RouteValueDictionary(values);
//redirect the request to MissingDatabase action method.
context.Result = new RedirectToRouteResult(r);
}
base.OnActionExecuting(context);
}
}
Here we are first checking whether the application variable has a valid entry for "DbSetDate" key. By default, it will not be there. Then you have to execute your custom code to check whether your db exist. If not, Redirect to the LoadScreen action.
Register this filter globally so that it will be executed for any request coming to your application.
GlobalFilters.Filters.Add(new VerifySetupIsGood());
Now in when you are done with setting up your database, update this application variable to have a valid value.
HttpContext.Application["DbSetDate"] = DateTime.Now.ToString();
Remember, Application variable states will also gets reset. So don't just rely on that. You should run your custom code to check your db exists inside the if condition. If condition is to prevent your custom db check for every single request.

MVC global exceptions

I am coding an MVC 5 internet application, and I have a question in regards to handling exceptions globally.
I have my Application_Error setup in my global.asax file. This caters to errors such as 404 HttpExceptions.
How can I send all errors that occur in a controller to the Application_Error function? An example is the following exception:
System.Web.HttpRequestValidationException: A potentially dangerous
Request.Form value was detected from the client (name="").
I have written a OnException(ExceptionContext filterContext) for my controller, but am not sure on how to get the Application_Error function to handle these errors. Do I need to pass the exception from the OnException function, or is this the wrong approach?
Thanks in advance.
You can create a global filter by adding the following class to your App_Start folder:-
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
}
HandleErrorAttribute can be replaced with your own custom Exception Filter.
All you then need to do is make sure you add the following line of code to the App_Start method of your Gloabal.asax :-
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
//AreaRegistration.RegisterAllAreas();
//RouteConfig.RegisterRoutes(RouteTable.Routes);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
}
}
Hope this helps.
I'm using some kind of http-module which gives me exactly what you are asking for:
public class MyModule : IHttpModule {
public void Init(HttpApplication context) {
context.Error += OnRequestError;
}
private void OnRequestError(object sender, EventArgs e) {
var context = ((HttpApplication)sender).Context;
var error = context.Error;
if (error == null)
return;
var errorType = error.GetType();
if (errorType == typeof(HttpException))
// do something
// this is what you are looking for
if (errorType = typeof(HttpRequestValidationException))
// do something, whatever you want
// works for me, so should work to you too
}
}
To get the module to work, you can use web.config or DynamicModuleHelper:
Install Microsoft.Web.Infrastructure and WebActivatorEx via nuget
Add a Bootstrapper class to your project
Register module at PreApplicationStartMethod
Sample:
// File: Bootstrapper.cs (contains class Bootstrapper)
using Microsoft.Web.Infrastructure.DynamicModuleHelper;
using WebActivatorEx;
using WhatEver.It.Is;
[assembly: PreApplicationStartMethod(typeof(Bootstrapper), "Bootstrap")]
namespace WhatEver.It.Is {
public class Bootstrapper {
public static void Bootstrap() {
// Do what do you need just before the application get started
// like registering modules, etc...
DynamicModuleUtility.RegisterModule(typeof(MyModule));
}
}
}

How to call controller method in global.asax?

I want to call controller method in Global.asax. Code is given below.
protected void Application_PostAuthenticateRequest(Object sender, EventArgs e)
{
if (User.Identity.IsAuthenticated)
{
//here we can subscribe user to a role via Roles.AddUserToRole()
}
}
This event is in global.asax. I want to call controller method which return user permissions from database. How this is possible to call controller method here after that I will save user permissions in session and my controller constructor? Code is given below.
public class AccountController : Controller
{
private readonly ISecurityService securityService;
public AccountController(ISecurityService securityService)
{
this.securityService = securityService;
}
}
Please guide me.
You could handle this using a custom AuthorizeAttribute. This allows you to place an attribute on the top of any controllers / methods which you require authentication to be successful in order to call. This lets you override AuthorizeCore which you can then use to do any custom authorization you want to perform. You can also save any other information to session from this method.
For example:
public class CustomAuthorizeAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
// do your own athorization stuff here
}
}
Then you can decorate you controllers that require the use of this authorization either with your attribute:
[CustomAuthorize]
public class AccountController : Controller
{
}
Or using a base controller:
[CustomAuthorize]
public class BaseAuthController : Controller
{
}
public class AccountController : BaseAuthController
{
}
i Resolve this issue by my self i call service method in global.asax by resolving dependency issue below is the solution of the above problem.
protected void Application_PostAuthenticateRequest(Object sender, EventArgs e)
{
if (User.Identity.IsAuthenticated)
{
IUnityContainer container = GetUnityContainer();
ISecurityService securityService = container.Resolve<SecurityService>();
var list = securityService.GetUserRolesandPermissions("1");
}
}
Thank you every one.

You must call the "WebSecurity.InitializeDatabaseConnection" but I DO

*You must call the "WebSecurity.InitializeDatabaseConnection" method before you call any other method of the "WebSecurity" class. This call
should be placed in an _AppStart.cshtml file in the root of your
site.*
I am getting this error, on and off, randomly and not sure what the reason is. In my route config. Index controller, index action is the default one. and here is the definition:
[Authorize(Roles = "admin")]
[InitializeSimpleMembership]
public class IndexController : Controller
Everytime I restart the application, if i didnt log out, i get the above error. Then I log out and log in again and error disappears.
Why is that happening?
How can i resolve this?
I am using localdb if that would help.
The problem occurs because the Application_Start() function only triggers on the first user action. But the IndexController is triggered before the user can event perform an action. Just remove the [InitializeSimpleMembership] from your project, It also gave me a lot of frustration...
Just add the following code to your global.asax
private static SimpleMembershipInitializer _initializer;
private static object _initializerLock = new object();
private static bool _isInitialized;
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
AuthConfig.RegisterAuth();
LazyInitializer.EnsureInitialized(ref _initializer, ref _isInitialized, ref _initializerLock);
}
public class SimpleMembershipInitializer
{
public SimpleMembershipInitializer()
{
using (var context = new UsersContext())
context.UserProfiles.Find(1);
if (!WebSecurity.Initialized)
WebSecurity.InitializeDatabaseConnection("DefaultConnection", "UserProfile", "UserId", "UserName", autoCreateTables: true);
}
}
Of course make sure you create the correct dbContext() and have the correct InitializeDatabaseConnections properties set that match your project.
Kr

Categories