This project allows for clients to insure various types of risk items (wheelchair/vehicle/scooter). For each risk item a different route was created (as different questions are asked for each type). Currently a risk item can be chosen and the client then fills in all their information, get a quote and then incept the policy (pay via credit/debit card). This application was created to only insure one risk item per policy. All of this works fine if a client only wants to insure one risk item. If the client then select to insure a different risk (or another) item a problem persist as the browser now holds the session of the previous request.
I need a to find a way to allow for different (or the same) risk items to be quoted and incepted without interfering with a previous policy inception (payment). When a client chooses a risk item (from a different website) it will navigate to the first start point of the risk item opening a different tab. Is it possible to maintain a session per tab?
This is what was done...
Register routes (File referenced to Global.asax)
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapMvcAttributeRoutes();
routes.MapRoute(
name: "Scooter",
url: "Scooter/{action}/{id}",
defaults: new { controller = "Mobility", action = "All", id = UrlParameter.Optional}
);
routes.MapRoute(
name: "Wheelchair",
url: "Wheelchair/{action}/{id}",
defaults: new { controller = "Mobility", action = "All", id = UrlParameter.Optional }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "ComingSoon", id = UrlParameter.Optional }
);
}
}
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
BundleMobileConfig.RegisterBundles(BundleTable.Bundles);
//Add a required data annotation that relies on the value of another property to set the field as required
DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(RequiredIfAttribute),typeof(RequiredAttributeAdapter));
}
Creating the sessions:
#region Helpers
private static T GetSession<T>(string key)
{
object value = HttpContext.Current.Session[key];
if (value == null)
return default(T);
else
return ((T)value);
}
private static void SetSession(string key, object value)
{
HttpContext.Current.Session[key] = value;
}
public static void ClearQuoteSession()
{
HttpContext.Current.Session.Clear();
HttpContext.Current.Session.Abandon();
}
public static string GenerateBuyMapCode()
{
var holderKey = Guid.NewGuid();
var polMapCode = "BB-" + holderKey;
return polMapCode.Trim();
}
The following method allows for the sessions to be created with the cookie.
public static PolicyBase CreateNewPolicyBase(Enums.RiskType type)
{
var polBase = new PolicyBase();
polBase.Insured = new InsuredViewModel();
polBase.RiskMeItems = new List<RiskItemMeModel>();
*Irrelevant code removed*
polBase.SessionKey = GenerateBuyMapCode();
polBase.BrowserSession = HttpContext.Current.Session;
*Irrelevant code removed*
return polBase;
}
#region Session INIT
public static string QuoteKey
{
get { return GetSession<string>("QuoteKey"); }
set { SetSession("QuoteKey", value); }
}
public static AusEnums.RiskType RiskType
{
get { return GetSession<AusEnums.RiskType>("RiskType"); }
set { SetSession("RiskType", value); }
}
public static AusEnums.QuoteArea Area
{
get { return GetSession<AusEnums.QuoteArea>("QuoteArea"); }
set { SetSession("QuoteArea", value); }
}
public static PolicyBase PolicyBase
{
get { return GetSession<PolicyBase>("PolicyBase"); }
set { SetSession("PolicyBase", value); }
}
public static SSMultiPremium MultiPremium
{
get { return GetSession<SSMultiPremium>("MultiPremium"); }
set { SetSession("MultiPremium", value); }
}
The web.config
<sessionState mode="InProc" cookieless="UseDeviceProfile" regenerateExpiredSessionId="true" timeout="20" />
The mobility and motor risk items have different start points, the following is the start point of the mobility (customer follows the principle)
[HttpGet]
[OutputCache(NoStore = true, Duration = 0, VaryByParam = "None")]
public ActionResult Insured()
{
//We need to determine the direction
SessionHelper.GetRoutePath((Route)ControllerContext.RouteData.Route);
var polBase = SessionHelper.PolicyBase;
HttpCookie userCookie = new HttpCookie("BBCookieCheck");
userCookie["Name"] = "BB";
userCookie.Expires.AddDays(1); // cookie will expire after 1 days
Response.Cookies.Add(userCookie);
var viewModel = new InsuredViewModel();
if (polBase != null)
{
viewModel = polBase.Insured;
viewModel.Title = polBase.Insured.Title;
}
viewModel.riskType = SessionHelper.RiskType;
*Irrelevant code removed*
return View(viewModel);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Insured(InsuredViewModel model)
{
*Irrelevant code removed*
//create a new quote object and save the relevant fields
var polBase = SessionHelper.PolicyBase;
if (model.Id == 0)
{
polBase = SessionHelper.CreateNewPolicyBase(model.riskType);
*Irrelevant code removed*
}
}
It appears your use case might benefit from a cookieless session state tracking. It also appears you are pretty much there.
<sessionState cookieless="UseUri" regenerateExpiredSessionId="true" timeout="20" />
UseDeviceProfile
pretty much means that any modern browser would resort to using cookies. But if you specifically lock it to UseUri
your might get better results.
In this case your GetSession<string>("XXX")
probably becomes redundant as each session would only relate to one policy flow