asp.net membership sometmies fails in production - asp.net-mvc-3

I have an ASP.NET MVC 3 application using ASP.NET Membership. I get strange error in production environment. One client complains that they always get an error when they try to log in using Chrome. It works with IE. However for another client they get same error when they log in with IE but works in Chrome.
This is the code for Logon
[HttpPost]
public ActionResult LogOn(LogOnModel model, string returnUrl)
{
if (ModelState.IsValid)
{
if (Membership.ValidateUser(model.UserName, model.Password))
{
FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
if (Url.IsLocalUrl(returnUrl) && returnUrl.Length > 1 && returnUrl.StartsWith("/")
&& !returnUrl.StartsWith("//") && !returnUrl.StartsWith("/\\"))
{
if (returnUrl.Contains("CorporaClaim"))
ViewBag.Layout = _corporaLayout;
else
ViewBag.Layout = _layout;
return Redirect(returnUrl);
}
else
{
ViewBag.Layout = _layout;
// redirect user according to user role
if (!string.IsNullOrEmpty(model.UserName))
return RedirectToDentalinkActionBasedOnRole(model.UserName);
}
}
else
{
ModelState.AddModelError("", "The user name or password provided is incorrect.");
}
}
ViewBag.Layout = _layout;
// If we got this far, something failed, redisplay form
return View(model);
}
In my _Layout.cshtml I make a call to the below method to show the logged in user's name:
#{
string displayName = DentalinkWeb.Utility.LoginUtility.GetDisplayForUser(User);
}
public class LoginUtility
{
public static string GetDisplayForUser(IPrincipal User)
{
string displayName = "";
if (User.Identity.IsAuthenticated)
{
if (User.IsInRole("Practice Admin"))
{
DentalinkEntities db = new DentalinkEntities();
RegisteredPractice prac = (from p in db.RegisteredPractices where p.Email == User.Identity.Name select p).FirstOrDefault();
displayName = prac.DentistFirstName + " " + prac.DentistSurname;
}
else if (User.IsInRole("Dentalink Admin"))
{
displayName = "Dentalink Admin";
}
}
return displayName;
}
}
}
We get this error:
System.NullReferenceException: Object reference not set to an instance of an object.
at DentalinkWeb.Utility.LoginUtility.GetDisplayForUser(IPrincipal User)
at ASP._Page_Views_Shared__Layout_cshtml.Execute() in e:\web\dentalinkco\htdocs\Views\Shared\_Layout.cshtml:line 51
at System.Web.WebPages.WebPageBase.ExecutePageHierarchy()
at System.Web.Mvc.WebViewPage.ExecutePageHierarchy()
at System.Web.WebPages.WebPageBase.ExecutePageHierarchy(WebPageContext pageContext, TextWriter writer, WebPageRenderingBase startPage)
at System.Web.WebPages.WebPageBase.<>c__DisplayClass7.<RenderPageCore>b__6(TextWriter writer)
at System.Web.WebPages.HelperResult.WriteTo(TextWriter writer)
at System.Web.WebPages.WebPageBase.Write(HelperResult result)
at System.Web.WebPages.WebPageBase.RenderSurrounding(String partialViewName, Action`1 body)
at System.Web.WebPages.WebPageBase.PopContext()
at System.Web.WebPages.WebPageBase.ExecutePageHierarchy(WebPageContext pageContext, TextWriter writer, WebPageRenderingBase startPage)
at System.Web.Mvc.RazorView.RenderView(ViewContext viewContext, TextWriter writer, Object instance)
at System.Web.Mvc.BuildManagerCompiledView.Render(ViewContext viewContext, TextWriter writer)
at System.Web.Mvc.ViewResultBase.ExecuteResult(ControllerContext context)
at System.Web.Mvc.ControllerActionInvoker.InvokeActionResult(ControllerContext controllerContext, ActionResult actionResult)
at System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName)
at System.Web.Mvc.Controller.ExecuteCore()
at System.Web.Mvc.ControllerBase.Execute(RequestContext requestContext)
at System.Web.Mvc.ControllerBase.System.Web.Mvc.IController.Execute(RequestContext requestContext)
at System.Web.Mvc.MvcHandler.<>c__DisplayClass6.<>c__DisplayClassb.<BeginProcessRequest>b__5()
at System.Web.Mvc.Async.AsyncResultWrapper.<>c__DisplayClass1.<MakeVoidDelegate>b__0()
at System.Web.Mvc.Async.AsyncResultWrapper.<>c__DisplayClass8`1.<BeginSynchronous>b__7(IAsyncResult _)
at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult`1.End()
at System.Web.Mvc.MvcHandler.<>c__DisplayClasse.<EndProcessRequest>b__d()
at System.Web.Mvc.SecurityUtil.<GetCallInAppTrustThunk>b__0(Action f)
at System.Web.Mvc.SecurityUtil.ProcessInApplicationTrust(Action action)
at System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult)
at System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult result)
at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)
Please help.

Only thing I can think of will be to add User != null in if statement.
if (User != null && User.Identity.IsAuthenticated)
{
...
RegisteredPractice prac = (from p in db.RegisteredPractices
where p.Email == User.Identity.Name select p).FirstOrDefault();
if(prac != null) // Just to be on safe side.
{
displayName = prac.DentistFirstName + " " + prac.DentistSurname;
}
...
}

Here's a revised code.
public class LoginUtility
{
public static string GetDisplayForUser(IPrincipal User)
{
string displayName = "";
if (User != null)
{
if (User.Identity.IsAuthenticated)
{
if (User.IsInRole("Practice Admin"))
{
DentalinkEntities db = new DentalinkEntities();
RegisteredPractice prac = (from p in db.RegisteredPractices where p.Email == User.Identity.Name select p).FirstOrDefault();
displayName = prac.DentistFirstName + " " + prac.DentistSurname;
}
else if (User.IsInRole("Dentalink Admin"))
{
displayName = "Dentalink Admin";
}
}
}
return displayName;
}
}

Related

Web api 2 with a data access layer called by the web api controller method. Getting casting error

I'm getting:
Unable to cast object of type 'System.Net.Http.HttpResponseMessage' to type 'System.Web.Http.IHttpActionResult
Web api2 controller method calls a data access layer that returns an int. It fails on the cast:
return (IHttpActionResult)httpResponse;
Code:
[HttpGet]
[Route("registeruser/{currentDateTime}/{userName}/{userPassword}/{ipAddress}/")]
public IHttpActionResult RegisterUser(DateTime currentDateTime, string userName, string userPassword, string ipAddress)
{
try
{
HttpResponseMessage httpResponse;
int returnValue = 0;
returnValue = dataaccesslayer.RegisterUser(currentDateTime, userName, userPassword, ipAddress);
httpResponse = Request.CreateResponse(HttpStatusCode.OK, returnValue);
return (IHttpActionResult)httpResponse;
}
catch (Exception)
{
throw;
}
}
Data access layer called by web api2 controller method - it returns an int:
public int RegisterUser(DateTime currentDateTime, string userName, string userPassword, string ipAddress)
{
int returnedValue = 0;
try
{
dbFunc.OpenDB();
SqlCommand cmd = new SqlCommand("dbo.RegisterUser", dbFunc.objConn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Clear();
cmd.Parameters.AddWithValue("#a_CurrentDateTime", currentDateTime);
cmd.Parameters.AddWithValue("#a_UserName", userName);
cmd.Parameters.AddWithValue("#a_UserPassword", userPassword);
cmd.Parameters.AddWithValue("#a_IpAddress", ipAddress);
cmd.Parameters.Add("#a_UserIdOut", SqlDbType.Int);
cmd.Parameters["#a_UserIdOut"].Direction = ParameterDirection.Output;
cmd.ExecuteNonQuery();
returnedValue = (int)cmd.Parameters["#a_UserIdOut"].Value;
return returnedValue;
}
catch (SqlException sqlex)
{
throw sqlex;
}
catch (Exception ex)
{
throw ex;
}
finally
{
// Close the database.
dbFunc.CloseDB();
}
}
If you want to keep the IHttpActionResult try this:
[HttpGet]
[Route("registeruser/{currentDateTime}/{userName}/{userPassword}/{ipAddress}/")]
public IHttpActionResult RegisterUser(DateTime currentDateTime, string userName, string userPassword, string ipAddress)
{
try
{
IHttpActionResult response;
HttpResponseMessage httpResponse;
int returnValue = 0;
returnValue = dataaccesslayer.RegisterUser(currentDateTime, userName, userPassword, ipAddress);
httpResponse = Request.CreateResponse(HttpStatusCode.OK, returnValue);
response = ResponseMessage(httpResponse);
return response;
}
catch (Exception)
{
throw;
}
}
If it is no problem for you to remove it, then do it like this:
[HttpGet]
[Route("registeruser/{currentDateTime}/{userName}/{userPassword}/{ipAddress}/")]
public HttpResponseMessage RegisterUser(DateTime currentDateTime, string userName, string userPassword, string ipAddress)
{
try
{
HttpResponseMessage httpResponse;
int returnValue = 0;
returnValue = dataaccesslayer.RegisterUser(currentDateTime, userName, userPassword, ipAddress);
httpResponse = Request.CreateResponse(HttpStatusCode.OK, returnValue);
return httpResponse;
}
catch (Exception)
{
throw;
}
}
For a longer discussion on between the two, check this link here.

Derived types are not published to consumers in MassTransit

I am having issues publishing generic messages for derived types and having the handler invoked using MassTransit v2.8.0.
If I publish a message of type HtmlBlockNewMessage, the consumer is never invoked. If I publish a ServiceBusMessage object and change the consumer to Consumes<ServiceBusMessage>.Context, the consumer is invoked.
The code fails for a derived type. It only works for the parent type (ServiceBusMessage).
Types:
[Serializable]
public class ServiceBusMessage
{
}
[Serializable]
public class ServiceBusResponse
{
public int ResultCode { get; set; }
}
// Request
[Serializable]
public class ContentItemMessage : ServiceBusMessage
{
public string SiteId { get; set; }
public string PageId { get; set; }
public string ContentItemId { get; set; }
}
[Serializable]
public class HtmlBlockNewMessage : ContentItemMessage
{
public string HtmlData { get; set; }
}
// Response
[Serializable]
public class ContentItemMessageResponse : ServiceBusResponse
{
public string Name { get; set; }
public string ItemType { get; set; }
public string ItemHandler { get; set; }
}
[Serializable]
public class HtmlBlockNewMessageResponse : ContentItemMessageResponse
{
public string DataId { get; set; }
}
Consumer:
public class HtmlBlockConsumer : Consumes<HtmlBlockNewMessage>.Context
{
private IHtmlDataService htmlDataService;
public static ILogger Logger { get; set; }
public HtmlBlockConsumer()
: this(null)
{
}
public HtmlBlockConsumer(IHtmlDataService htmlDataService)
{
Logger = Log4NetLogger.GetLogger();
this.htmlDataService = htmlDataService ?? IoC.Container.Resolve<IHtmlDataService>();
}
public void Consume(IConsumeContext<HtmlBlockNewMessage> message)
{
// Do some stuff
message.Respond(new HtmlBlockNewMessageResponse() { ResultCode = 1 } );
}
}
Bus registration from publisher side:
var bus = ServiceBusFactory.New(sbc =>
{
sbc.EnableMessageTracing();
sbc.UseMsmq();
sbc.VerifyMsmqConfiguration();
sbc.UseMulticastSubscriptionClient();
sbc.SetNetwork("Test");
sbc.UseXmlSerializer();
sbc.UseControlBus();
sbc.ReceiveFrom("msmq://localhost/AuctionCMS.Web.Publisher");
MtServiceBus.ValidateBus(sbc);
});
IoC.Container.RegisterInstance(bus);
Bus registration from consumer side:
var bus = ServiceBusFactory.New(sbc =>
{
sbc.EnableMessageTracing();
sbc.UseMsmq();
sbc.VerifyMsmqConfiguration();
sbc.UseMulticastSubscriptionClient();
sbc.SetNetwork("Test");
sbc.UseXmlSerializer();
sbc.UseControlBus();
sbc.ReceiveFrom("msmq://localhost/AuctionCMS.Consumer");
sbc.Subscribe(subs =>
{
// These are being manually registered due to some issues getting
// StructureMap to scan my assemblies
subs.Instance(new HtmlBlockConsumer());
subs.Instance(new BrowserConsumer());
subs.Instance(new OfferConsumer());
});
});
IoC.Container.RegisterInstance(bus);
My publish extension:
public static TR Publish<T, TR>(this IServiceBus bus, T message) where T : ServiceBusMessage where TR : ServiceBusResponse
{
TR response = null;
IoC.Container.Resolve<IServiceBus>().PublishRequest(message, callback =>
{
callback.SetTimeout(10.Seconds());
try
{
callback.Handle<TR>(m =>
{
response = m; /
});
}
catch (Exception ex)
{
throw;
}
});
return response;
}
Calling code:
// First I create a message specific to the type of action I am performing
var message = new HtmlBlockNewMessage() { HtmlData = "Hello" };
// Then I call a function which accepts a ContentItemMessage and calls Publish
public void AddContentItem(ContentItemMessage message)
{
// Do some preprocessing
// This call times out
var response = this.auctionCmsServices.Bus.Publish<ContentItemMessage,
ContentItemMessageResponse>(message);
// Do some more processing
}
This is the exception
[RequestTimeoutException: Timeout waiting for response, RequestId: 54910000-307f-20cf-c0c2-08d06b31cf6f]
MassTransit.RequestResponse.RequestImpl`1.Wait() in d:\BuildAgent-03\work\aa063b4295dfc097\src\MassTransit\RequestResponse\RequestImpl.cs:124
MassTransit.RequestResponseExtensions.PublishRequest(IServiceBus bus, TRequest message, Action`1 configureCallback) in d:\BuildAgent-03\work\aa063b4295dfc097\src\MassTransit\RequestResponseExtensions.cs:31
AuctionCMS.Framework.ServiceBus.MtServiceBus.Publish(IServiceBus bus, T message) in c:\Users\rick\Documents\Visual Studio 2012\Projects\AuctionCMS\AuctionCMS.Framework\ServiceBus\MtServiceBus.cs:24
AuctionCMS.Framework.Entity.Page.AddContentItem(ISite site, String zone, Int32 location, ContentItemMessage message) in c:\Users\rick\Documents\Visual Studio 2012\Projects\AuctionCMS\AuctionCMS.Framework\Entity\Page.cs:48
AuctionCMS.Framework.Entity.Site.SetDefaultContent() in c:\Users\rick\Documents\Visual Studio 2012\Projects\AuctionCMS\AuctionCMS.Framework\Entity\Site.cs:117
AuctionCMS.Web.Controllers.AdminSitesController.NewSite(SiteNewModel model, HttpPostedFileBase file) in c:\Users\rick\Documents\Visual Studio 2012\Projects\AuctionCMS\AuctionCMS.Web\Controllers\AdminSitesController.cs:69
lambda_method(Closure , ControllerBase , Object[] ) +179
System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters) +261
System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters) +39
System.Web.Mvc.Async.<>c__DisplayClass42.<BeginInvokeSynchronousActionMethod>b__41() +34
System.Web.Mvc.Async.<>c__DisplayClass39.<BeginInvokeActionMethodWithFilters>b__33() +124
System.Web.Mvc.Async.<>c__DisplayClass4f.<InvokeActionMethodFilterAsynchronously>b__49() +838059
System.Web.Mvc.Async.<>c__DisplayClass4f.<InvokeActionMethodFilterAsynchronously>b__49() +838059
System.Web.Mvc.Async.<>c__DisplayClass4f.<InvokeActionMethodFilterAsynchronously>b__49() +838059
System.Web.Mvc.Async.<>c__DisplayClass4f.<InvokeActionMethodFilterAsynchronously>b__49() +838059
System.Web.Mvc.Async.<>c__DisplayClass37.<BeginInvokeActionMethodWithFilters>b__36(IAsyncResult asyncResult) +15
System.Web.Mvc.Async.<>c__DisplayClass2a.<BeginInvokeAction>b__20() +33
System.Web.Mvc.Async.<>c__DisplayClass25.<BeginInvokeAction>b__22(IAsyncResult asyncResult) +838644
System.Web.Mvc.<>c__DisplayClass1d.<BeginExecuteCore>b__18(IAsyncResult asyncResult) +28
System.Web.Mvc.Async.<>c__DisplayClass4.<MakeVoidDelegate>b__3(IAsyncResult ar) +15
System.Web.Mvc.Controller.EndExecuteCore(IAsyncResult asyncResult) +65
System.Web.Mvc.Async.<>c__DisplayClass4.<MakeVoidDelegate>b__3(IAsyncResult ar) +15
System.Web.Mvc.Controller.EndExecute(IAsyncResult asyncResult) +51
System.Web.Mvc.<>c__DisplayClass8.<BeginProcessRequest>b__3(IAsyncResult asyncResult) +42
System.Web.Mvc.Async.<>c__DisplayClass4.<MakeVoidDelegate>b__3(IAsyncResult ar) +15
System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult) +51
System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +606
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +288
Edit:
I went with a generic approach to solve this. It's a but ugly from the caller's perspective, but it works.
public TR AddContentItem<T, TR>(T message) where T : ContentItemMessage where TR : ContentItemMessageResponse
{
var response = this.auctionCmsServices.Bus.Publish<T, TR>(message);
return response;
}
The calling code now looks like this:
page.AddContentItem(new HtmlBlockNewMessage() { HtmlData =
"This is some html" });
Eugene's comment is correct. What's happening here is you are publishing a message of type ContentItemMessage. A consumer of HtmlBlockNewMessage will not executed since the message is published as a ContentItemMessage and a ServiceBusMessage. MassTransit message mis-typing is one of a number of things out there on how this works.
Your options:
Change AddContentItem to use a generic, perhaps with a constraint
Used reflection to invoke Publish with the right type information
Restructure how you publish things so this isn't an issue any more
The bottom line is you should always publish as the type you want received. Polymorphism in messaging is tricky.

ASP.NET MVC 3 Localization using route and view

I have searched and tried many localization approaches but all is not exactly what I want. Basically, I want to have my url like this
www.myweb.com <== default language (which is English)
www.myweb.com/promotion
www.myweb.com/th/promotion <== local language (Thai)
www.myweb.com/cn/promotion <== local language (Chinese)
Then I want these url to map with different View structure as below
/Views
/_Localization
/cn
/Home
/About.cshtml
/Index.cshtml
/Shared
/_Layout.cshtml
/Error.cshtml
/th
/Home
/About.cshtml
/Shared
/Home
/About.cshtml
/Index.cshtml
/Shared
/_Layout.cshtml
/_LogOnPartial.cshtml
/Error.cshtml
_ViewStart.cshtml
Web.config
As you can seen, Thai doesn't have it own Index.cshtml, _Layout.cshtml and Error.cshtml. So, I would like this to fallback to use the default instead. But chinese will use it own.
I have tried to MapRoute like this
routes.MapRoute(
"DefaultLocal",
"{lang}/{controller}/{action}/{id}",
new { lang = "th", controller = "Home", action = "Index", id = UrlParameter.Optional }
);
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
but I don't know how to point to different View structure. And in this example, Brian Reiter, it use Cookie not url.
So, how can I achieve this. note that I use RazorViewEngine.
Thank you for any help and thought.
Due to large amount of code needed i will only illustrate an idea of how it could be done.
You can subclass from RazorViewEngine like this:
public class I18NRazorViewEngine : RazorViewEngine
{
public I18NRazorViewEngine() : this(null)
{ }
protected string[] I18NAreaViewLocationFormats;
protected string[] I18NAreaMasterLocationFormats;
protected string[] I18NAreaPartialViewLocationFormats;
protected string[] I18NViewLocationFormats;
protected string[] I18NMasterLocationFormats;
protected string[] I18NPartialViewLocationFormats;
public I18NRazorViewEngine(IViewPageActivator viewPageActivator)
: base(viewPageActivator)
{
this.I18NAreaViewLocationFormats = new string[]
{
"~/Areas/{3}/{2}/Views/{1}/{0}.cshtml",
"~/Areas/{3}/{2}/Views/{1}/{0}.vbhtml",
"~/Areas/{3}/{2}/Views/Shared/{0}.cshtml",
"~/Areas/{3}/{2}/Views/Shared/{0}.vbhtml"
};
this.I18NAreaMasterLocationFormats = new string[]
{
"~/Areas/{3}/{2}/Views/{1}/{0}.cshtml",
"~/Areas/{3}/{2}/Views/{1}/{0}.vbhtml",
"~/Areas/{3}/{2}/Views/Shared/{0}.cshtml",
"~/Areas/{3}/{2}/Views/Shared/{0}.vbhtml"
};
this.I18NAreaPartialViewLocationFormats = new string[]
{
"~/Areas/{3}/{2}/Views/{1}/{0}.cshtml",
"~/Areas/{3}/{2}/Views/{1}/{0}.vbhtml",
"~/Areas/{3}/{2}/Views/Shared/{0}.cshtml",
"~/Areas/{3}/{2}/Views/Shared/{0}.vbhtml"
};
this.I18NViewLocationFormats = new string[]
{
"~/Views/{2}/{1}/{0}.cshtml",
"~/Views/{2}/{1}/{0}.vbhtml",
"~/Views/{2}/Shared/{0}.cshtml",
"~/Views/{2}/Shared/{0}.vbhtml"
};
this.I18NMasterLocationFormats = new string[]
{
"~/Views/{2}/{1}/{0}.cshtml",
"~/Views/{2}/{1}/{0}.vbhtml",
"~/Views/{2}/Shared/{0}.cshtml",
"~/Views/{2}/Shared/{0}.vbhtml"
};
this.I18NPartialViewLocationFormats = new string[]
{
"~/Views/{2}/{1}/{0}.cshtml",
"~/Views/{2}/{1}/{0}.vbhtml",
"~/Views/{2}/Shared/{0}.cshtml",
"~/Views/{2}/Shared/{0}.vbhtml"
};
}
public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
{
var langValue = controllerContext.Controller.ValueProvider.GetValue("lang");
if (langValue == null || String.IsNullOrEmpty(langValue.AttemptedValue))
return base.FindView(controllerContext, viewName, masterName, useCache);
//Code here
}
public override ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache)
{
var langValue = controllerContext.Controller.ValueProvider.GetValue("lang");
if (langValue == null || String.IsNullOrEmpty(langValue.AttemptedValue))
return base.FindPartialView(controllerContext, partialViewName, useCache);
//Code here
}
}
The next what you should do is to look inside VirtualPathProviderViewEngine on FindView and FindPartialView inplementations. The reflected code is like this:
public virtual ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache)
{
if (controllerContext == null)
{
throw new ArgumentNullException("controllerContext");
}
if (string.IsNullOrEmpty(partialViewName))
{
throw new ArgumentException(MvcResources.Common_NullOrEmpty, "partialViewName");
}
string requiredString = controllerContext.RouteData.GetRequiredString("controller");
string[] searchedLocations;
string path = this.GetPath(controllerContext, this.PartialViewLocationFormats, this.AreaPartialViewLocationFormats, "PartialViewLocationFormats", partialViewName, requiredString, "Partial", useCache, out searchedLocations);
if (string.IsNullOrEmpty(path))
{
return new ViewEngineResult(searchedLocations);
}
return new ViewEngineResult(this.CreatePartialView(controllerContext, path), this);
}
and
public virtual ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
{
if (controllerContext == null)
{
throw new ArgumentNullException("controllerContext");
}
if (string.IsNullOrEmpty(viewName))
{
throw new ArgumentException(MvcResources.Common_NullOrEmpty, "viewName");
}
string requiredString = controllerContext.RouteData.GetRequiredString("controller");
string[] first;
string path = this.GetPath(controllerContext, this.ViewLocationFormats, this.AreaViewLocationFormats, "ViewLocationFormats", viewName, requiredString, "View", useCache, out first);
string[] second;
string path2 = this.GetPath(controllerContext, this.MasterLocationFormats, this.AreaMasterLocationFormats, "MasterLocationFormats", masterName, requiredString, "Master", useCache, out second);
if (string.IsNullOrEmpty(path) || (string.IsNullOrEmpty(path2) && !string.IsNullOrEmpty(masterName)))
{
return new ViewEngineResult(first.Union(second));
}
return new ViewEngineResult(this.CreateView(controllerContext, path, path2), this);
}
both methods rely on private GetPath method:
private string GetPath(ControllerContext controllerContext, string[] locations, string[] areaLocations, string locationsPropertyName, string name, string controllerName, string cacheKeyPrefix, bool useCache, out string[] searchedLocations)
{
searchedLocations = VirtualPathProviderViewEngine._emptyLocations;
if (string.IsNullOrEmpty(name))
{
return string.Empty;
}
string areaName = AreaHelpers.GetAreaName(controllerContext.RouteData);
List<VirtualPathProviderViewEngine.ViewLocation> viewLocations = VirtualPathProviderViewEngine.GetViewLocations(locations, (!string.IsNullOrEmpty(areaName)) ? areaLocations : null);
if (viewLocations.Count == 0)
{
throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, MvcResources.Common_PropertyCannotBeNullOrEmpty, new object[]
{
locationsPropertyName
}));
}
bool flag = VirtualPathProviderViewEngine.IsSpecificPath(name);
string text = this.CreateCacheKey(cacheKeyPrefix, name, flag ? string.Empty : controllerName, areaName);
if (useCache)
{
return this.ViewLocationCache.GetViewLocation(controllerContext.HttpContext, text);
}
if (!flag)
{
return this.GetPathFromGeneralName(controllerContext, viewLocations, name, controllerName, areaName, text, ref searchedLocations);
}
return this.GetPathFromSpecificName(controllerContext, name, text, ref searchedLocations);
}
What you should do is to reimplement it. Most of the code you can reuse, but you should create your own method instead of VirtualPathProviderViewEngine.GetViewLocations. Here its reflected code:
private static List<VirtualPathProviderViewEngine.ViewLocation> GetViewLocations(string[] viewLocationFormats, string[] areaViewLocationFormats)
{
List<VirtualPathProviderViewEngine.ViewLocation> list = new List<VirtualPathProviderViewEngine.ViewLocation>();
if (areaViewLocationFormats != null)
{
for (int i = 0; i < areaViewLocationFormats.Length; i++)
{
string virtualPathFormatString = areaViewLocationFormats[i];
list.Add(new VirtualPathProviderViewEngine.AreaAwareViewLocation(virtualPathFormatString));
}
}
if (viewLocationFormats != null)
{
for (int j = 0; j < viewLocationFormats.Length; j++)
{
string virtualPathFormatString2 = viewLocationFormats[j];
list.Add(new VirtualPathProviderViewEngine.ViewLocation(virtualPathFormatString2));
}
}
return list;
}
You can also reuse most of the code but instead of VirtualPathProviderViewEngine.ViewLocation and VirtualPathProviderViewEngine.AreaAwareViewLocation you should use your own classes. They could be like this:
class ViewLocation
{
protected string _virtualPathFormatString;
public ViewLocation(string virtualPathFormatString)
{
this._virtualPathFormatString = virtualPathFormatString;
}
public virtual string Format(string viewName, string controllerName, string areaName, string lang)
{
return string.Format(CultureInfo.InvariantCulture, this._virtualPathFormatString, new object[]
{
viewName,
controllerName,
lang
});
}
}
and:
class AreaAwareViewLocation : VirtualPathProviderViewEngine.ViewLocation
{
public AreaAwareViewLocation(string virtualPathFormatString) : base(virtualPathFormatString)
{
}
public override string Format(string viewName, string controllerName, string areaName, string lang)
{
return string.Format(CultureInfo.InvariantCulture, this._virtualPathFormatString, new object[]
{
viewName,
controllerName,
areaName,
lang
});
}
}
and then when you will call Format methods you should pass langValue.AttemptedValue (it is from scope of FindView and FindPartialView in the first code block) to lang parameter. Normally it's called in VirtualPathProviderViewEngine.GetPathFromGeneralName.
The main advice is to use ILSpy or another disassembler to explore the code of System.Web.Mvc (or even better - download its sources). The goal is to reimplement FindView and FindPartialView. The rest code provided is to illustrate how it's already done in mvc framework.
It's also important to to seek through arrays declared in our new view engine instead of those without I18N prefix which are already there and used by default classes
Hope it will help despite answer is indirect. You can ask additional questions if you will face any difficulties.
P.S. Don't foreget to register you view engine in global.asax.cs after it will be developed.
protected virtual void Application_Start()
{
ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new I18NRazorViewEngine());
}

Nhibenate - DOS Attack

One of the testers in my company found an error on my ASP.Net MVC 3 solution, that I believe is pretty common.
One post to the server it can handle. But if you send a lot of posts, like a denial-of-service attack (DoS attack) it thrown an exception:
Server Error in '/' Application.
Initializing[UseSoft.ProdMaster.Domain.Entities.CustomerOrderHeader#567]-failed to lazily initialize a collection of role: UseSoft.ProdMaster.Domain.Entities.CustomerOrderHeader.CustomerOrderLines, no session or session was closed
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: NHibernate.LazyInitializationException: Initializing[UseSoft.ProdMaster.Domain.Entities.CustomerOrderHeader#567]-failed to lazily initialize a collection of role: UseSoft.ProdMaster.Domain.Entities.CustomerOrderHeader.CustomerOrderLines, no session or session was closed
Source Error:
Line 880:
Line 881:
Line 882: return
Line 883: Json(
Line 884: new
Source File: C:\Projects\DavidPM\Hosts\ProdMaster.Hosts.Web\Areas\Sales\Controllers\CustomerOrderController.cs Line: 882
Stack Trace:
[LazyInitializationException: Initializing[UseSoft.ProdMaster.Domain.Entities.CustomerOrderHeader#567]-failed to lazily initialize a collection of role: UseSoft.ProdMaster.Domain.Entities.CustomerOrderHeader.CustomerOrderLines, no session or session was closed]
NHibernate.Collection.AbstractPersistentCollection.ThrowLazyInitializationException(String message) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Collection\AbstractPersistentCollection.cs:484
NHibernate.Collection.AbstractPersistentCollection.ThrowLazyInitializationExceptionIfNotConnected() in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Collection\AbstractPersistentCollection.cs:474
NHibernate.Collection.AbstractPersistentCollection.Initialize(Boolean writing) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Collection\AbstractPersistentCollection.cs:465
NHibernate.Collection.AbstractPersistentCollection.Read() in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Collection\AbstractPersistentCollection.cs:264
NHibernate.Collection.Generic.PersistentGenericBag`1.System.Collections.Generic.IEnumerable<T>.GetEnumerator() in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Collection\Generic\PersistentGenericBag.cs:142
System.Linq.WhereSelectEnumerableIterator`2.MoveNext() +63
System.Linq.Buffer`1..ctor(IEnumerable`1 source) +217
System.Linq.Enumerable.ToArray(IEnumerable`1 source) +78
UseSoft.ProdMaster.Hosts.Web.Areas.Sales.Controllers.CustomerOrderController.SaveOrUpdateOrderLines(CustomerOrderModel customerOrderModel) in C:\Projects\DavidPM\Hosts\ProdMaster.Hosts.Web\Areas\Sales\Controllers\CustomerOrderController.cs:882
lambda_method(Closure , ControllerBase , Object[] ) +162
System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters) +17
System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters) +208
System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters) +27
System.Web.Mvc.<>c__DisplayClass15.<InvokeActionMethodWithFilters>b__12() +55
System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func`1 continuation) +263
System.Web.Mvc.<>c__DisplayClass17.<InvokeActionMethodWithFilters>b__14() +19
System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodWithFilters(ControllerContext controllerContext, IList`1 filters, ActionDescriptor actionDescriptor, IDictionary`2 parameters) +191
System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName) +343
System.Web.Mvc.Controller.ExecuteCore() +116
System.Web.Mvc.ControllerBase.Execute(RequestContext requestContext) +97
System.Web.Mvc.ControllerBase.System.Web.Mvc.IController.Execute(RequestContext requestContext) +10
System.Web.Mvc.<>c__DisplayClassb.<BeginProcessRequest>b__5() +37
System.Web.Mvc.Async.<>c__DisplayClass1.<MakeVoidDelegate>b__0() +21
System.Web.Mvc.Async.<>c__DisplayClass8`1.<BeginSynchronous>b__7(IAsyncResult _) +12
System.Web.Mvc.Async.WrappedAsyncResult`1.End() +62
System.Web.Mvc.<>c__DisplayClasse.<EndProcessRequest>b__d() +50
System.Web.Mvc.SecurityUtil.<GetCallInAppTrustThunk>b__0(Action f) +7
System.Web.Mvc.SecurityUtil.ProcessInApplicationTrust(Action action) +22
System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult) +60
System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult result) +9
System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +8862381
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +184
The is described bellow:
Click in a button many times. Or click once and press enter, it will send a lot of requests to the server "Post".
The Model Basically is:
public class CustomerOrderModel
{
public CustomerOrderModel()
{
this.CustomerOrderLines = new List<CustomerOrderLineModel>();
this.CustomerOrderHeader = new CustomerOrderHeaderModel();
}
public CustomerOrderHeaderModel CustomerOrderHeader
{ get; set; }
public List<CustomerOrderLineModel> CustomerOrderLines
{ get; set; }
}
The Controller:
[HttpPost]
public JsonResult SaveOrUpdateOrderLines( CustomerOrderModel customerOrderModel)
{
if (customerOrderModel.CustomerOrderHeader.OrderNumber == 0)
{
customerOrderModel.CustomerOrderHeader.OrderNumber = this.CustomerOrderService.CreateOrUpdate(customerOrderHeader, false);
}
return
Json(
new
{
OrderNumber = customerOrderModel.CustomerOrderHeader.OrderNumber,
CustomerOrderLines = new
{
CustomerOrderLine = (
from ordeline in custOrderHeader.CustomerOrderLines
select new
{
Id = ordeline.Id,
LineNumber = ordeline.LineNumber,
LineStatus = ordeline.LineStatus
}
).ToArray()
}
},
JsonRequestBehavior.AllowGet
);
}
The CustomerOrder Service:
public class CustomerOrderService : ServiceBase, ICustomerOrderService
{
public long CreateOrUpdate(CustomerOrderHeader customerOrderHeader, bool updateCustomerOrderHeader)
{
using (var session = this.SessionManager.OpenSession())
{
var transaction = session.BeginTransaction();
try
{
//TODO: CHECKS IF PARTNER EXISTS
bool existsPartner = false;
long number = 0;
if (this.PartnerService.FindByName(customerOrderHeader.Partner.Name) != null)
{
existsPartner = true;
}
//CREATE PARTNER AND PARTNER ADDRESSES
if (!existsPartner)
{
this.PartnerService.Create(customerOrderHeader.Partner as Partner);
}
if (!updateCustomerOrderHeader)
{
number = this.CustomerOrderHeaderService.Create(customerOrderHeader, true);
}
else
{
this.CustomerOrderHeaderService.Create(customerOrderHeader, false);
}
transaction.Commit();
return number;
}
catch (Exception ex)
{
transaction.Rollback();
throw ex;
}
finally
{
session.Close();
}
}
}
/// <summary>
/// Initializes a new instance of the <see cref="CustomerOrderService"/> class.
/// </summary>
/// <param name="sessionManager">
/// The session manager.
/// </param>
public CustomerOrderService(ISessionManager sessionManager)
{
this.SessionManager = sessionManager;
}
}
The CustomerOrderHeaderService:
public long Create(CustomerOrderHeader customerOrderHeader, bool firstTime)
{
using (var session = this.SessionManager.OpenSession())
{
// var transaction = session.BeginTransaction();
// try
// {
if (firstTime)
{
foreach (var customerOrderLine in customerOrderHeader.CustomerOrderLines)
{
customerOrderLine.CustomerOrderHeader = customerOrderHeader;
}
customerOrderHeader.OrderNumber = this.NextOrderNumber();
session.Save(customerOrderHeader);
}
else
{
CustomerOrderHeader customerOrderHeaderToBeChanged =
this.FindByOrderNumber(customerOrderHeader.OrderNumber);
customerOrderHeaderToBeChanged.CopyDomainProperties(
customerOrderHeader, new[]
{
"Id",
"Partner",
"DataOwner",
"dataOwner",
"SysCreatedOn",
"SysCreatedBy",
"CustomerOrderLines"
});
customerOrderHeaderToBeChanged = UpdateLines(customerOrderHeader, customerOrderHeaderToBeChanged);
List<ICustomerOrderLine> linestoBeInserted = GetTheLineNumbersToBeInserted(customerOrderHeader);
foreach (var customerOrderLine in linestoBeInserted)
{
customerOrderHeaderToBeChanged.CustomerOrderLines.Add(customerOrderLine);
customerOrderLine.CustomerOrderHeader = customerOrderHeaderToBeChanged;
}
session.Update(customerOrderHeaderToBeChanged);
}
// transaction.Commit();
}
// catch (Exception ex)
// {
// transaction.Rollback();
// throw ex;
// }
// finally
// {
// session.Close();
// }
//}
//throw new System.ArgumentException();
return customerOrderHeader.OrderNumber;
}
public class CustomerOrderHeaderService : ServiceBase, ICustomerOrderHeaderService
{
#region Constructors and Destructors
/// <summary>
/// Initializes a new instance of the <see cref="CustomerOrderHeaderService"/> class.
/// </summary>
/// <param name="sessionManager">
/// The session manager.
/// </param>
public CustomerOrderHeaderService(ISessionManager sessionManager)
{
this.SessionManager = sessionManager;
}
#endregion
public long Create(CustomerOrderHeader customerOrderHeader, bool firstTime)
{
using (var session = this.SessionManager.OpenSession())
{
// var transaction = session.BeginTransaction();
// try
// {
if (firstTime)
{
foreach (var customerOrderLine in customerOrderHeader.CustomerOrderLines)
{
customerOrderLine.CustomerOrderHeader = customerOrderHeader;
}
customerOrderHeader.OrderNumber = this.NextOrderNumber();
session.Save(customerOrderHeader);
}
else
{
CustomerOrderHeader customerOrderHeaderToBeChanged =
this.FindByOrderNumber(customerOrderHeader.OrderNumber);
customerOrderHeaderToBeChanged.CopyDomainProperties(
customerOrderHeader, new[]
{
"Id",
"Partner",
"DataOwner",
"dataOwner",
"SysCreatedOn",
"SysCreatedBy",
"CustomerOrderLines"
});
customerOrderHeaderToBeChanged = UpdateLines(customerOrderHeader, customerOrderHeaderToBeChanged);
List<ICustomerOrderLine> linestoBeInserted = GetTheLineNumbersToBeInserted(customerOrderHeader);
foreach (var customerOrderLine in linestoBeInserted)
{
customerOrderHeaderToBeChanged.CustomerOrderLines.Add(customerOrderLine);
customerOrderLine.CustomerOrderHeader = customerOrderHeaderToBeChanged;
}
session.Update(customerOrderHeaderToBeChanged);
}
// transaction.Commit();
}
// catch (Exception ex)
// {
// transaction.Rollback();
// throw ex;
// }
// finally
// {
// session.Close();
// }
//}
//throw new System.ArgumentException();
return customerOrderHeader.OrderNumber;
}
}
Increase your connection pool limits can help make it last longer under this, as long as you don't saturate the server/network with too many.
Open and close database connections as late and early (respectively) as possible. You may want to switch your session open/close from per-request (or whatever you are using) to on-use.
In your case, since it's a button on the interface, you can temporarily disable it (with JavaScript) for a period of time so the user can't keep clicking it faster than they should ever need to.
Regardless, you should rate limit the incoming requests either at the network or IIS level.
Make sure that you aren't sharing objects across multiple NHibernate sessions.
That error could occur if Session #1 loads an object that Session #2 tries to commit.

Deserialize Json to class object using restsharp

I have checked out the documentation for restsharp and also googled for a solution, but unable to find a solution for this problem:
I have an asp.net mvc3 app and need to connect to quizlet.com to access public flashcards. I have added a reference to restsharp and created the following classes:
public class QuizletObject
{
public string response_type { get; set; }
public int total_results { get; set; }
public int page { get; set; }
public int total_pages { get; set; }
public int sets_with_images { get; set; }
public Set[] sets { get; set; }
}
public class Set
{
public int id { get; set; }
public string title { get; set; }
public string url { get; set; }
public string creator { get; set; }
public int created { get; set; }
public int term_count { get; set; }
public bool has_images { get; set; }
public int last_modified { get; set; }
}
I have a class and method that calls the web service like this:
public class Quizlet
{
private string _baseUrl = "http://api.quizlet.com/1.0/sets";
private const string DevKey = "my dev key";
public QuizletObject GetQuizletSets()
{
_baseUrl = _baseUrl + "?dev_key=" + DevKey + "&q=" + "geography";
RestClient client = new RestClient();
client.BaseUrl = _baseUrl;
RestRequest request = new RestRequest(Method.GET);
request.RequestFormat = DataFormat.Json;
RestResponse<QuizletObject> response = client.Execute<QuizletObject>(request);
return response.Data;
}
}
When I try to access the method using the below code in the view, I get a NullReference exception (Object reference not set to an instance of an object).
#{
QuizletObject quizletObject = quizlet.GetQuizletSets();
}
#foreach (Set quizletSet in quizletObject.sets)
{
#quizletSet.id.ToString()
<br />
#quizletSet.title
<br />
#quizletSet.creator
<br />
#quizletSet.created
<br />
#Html.Encode(quizletSet.url)
<br />
<br />
}
If the same method is executed as below, it returns the complete json object without any problem
RestResponse response = client.Execute(request);
Stack trace:
[NullReferenceException: Object reference not set to an instance of an object.]
ASP._Page_Views_Home_Index_cshtml.Execute() in c:\Users\Girish\Documents\Visual Studio 2010\Projects\RestSharpPoC\RestSharpPoC\Views\Home\Index.cshtml:18
System.Web.WebPages.WebPageBase.ExecutePageHierarchy() +207
System.Web.Mvc.WebViewPage.ExecutePageHierarchy() +81
System.Web.WebPages.StartPage.RunPage() +19
System.Web.WebPages.StartPage.ExecutePageHierarchy() +65
System.Web.WebPages.WebPageBase.ExecutePageHierarchy(WebPageContext pageContext, TextWriter writer, WebPageRenderingBase startPage) +76
System.Web.Mvc.RazorView.RenderView(ViewContext viewContext, TextWriter writer, Object instance) +220
System.Web.Mvc.BuildManagerCompiledView.Render(ViewContext viewContext, TextWriter writer) +115
System.Web.Mvc.ViewResultBase.ExecuteResult(ControllerContext context) +303
System.Web.Mvc.ControllerActionInvoker.InvokeActionResult(ControllerContext controllerContext, ActionResult actionResult) +13
System.Web.Mvc.<>c__DisplayClass1c.<InvokeActionResultWithFilters>b__19() +23
System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilter(IResultFilter filter, ResultExecutingContext preContext, Func`1 continuation) +260
System.Web.Mvc.<>c__DisplayClass1e.<InvokeActionResultWithFilters>b__1b() +19
System.Web.Mvc.ControllerActionInvoker.InvokeActionResultWithFilters(ControllerContext controllerContext, IList`1 filters, ActionResult actionResult) +177
System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName) +343
System.Web.Mvc.Controller.ExecuteCore() +116
System.Web.Mvc.ControllerBase.Execute(RequestContext requestContext) +97
System.Web.Mvc.ControllerBase.System.Web.Mvc.IController.Execute(RequestContext requestContext) +10
System.Web.Mvc.<>c__DisplayClassb.<BeginProcessRequest>b__5() +37
System.Web.Mvc.Async.<>c__DisplayClass1.<MakeVoidDelegate>b__0() +21
System.Web.Mvc.Async.<>c__DisplayClass8`1.<BeginSynchronous>b__7(IAsyncResult _) +12
System.Web.Mvc.Async.WrappedAsyncResult`1.End() +62
System.Web.Mvc.<>c__DisplayClasse.<EndProcessRequest>b__d() +50
System.Web.Mvc.SecurityUtil.<GetCallInAppTrustThunk>b__0(Action f) +7
System.Web.Mvc.SecurityUtil.ProcessInApplicationTrust(Action action) +22
System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult) +60
System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult result) +9
System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +8963149
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +184
I have seen the same issue. I haven't figured it out in RestSharp, but what I do to work around it is get the json text back then deserialize it myself.
For your code maybe something like this would work:
response = client.Execute(request);
var quizletObject = Newtonsoft.Json.JsonConvert.DeserializeObject<QuizletObject>(response.Content);
As an aside, it looks like you have a problem in your GetQuizletSets() call - each time you call it, it appends _baseUrl to itself so it will continually get longer and longer.
You should keep the base url the same and use request.Resource to specify the parameters, this case it would be:
request.Resource = "?dev_key=" + DevKey + "&q=" + "geography"
If there are multiple available calls you want to make besides "sets" I might set it up like this:
private string _baseUrl = "http://api.quizlet.com/1.0";
...
request.Resource = "sets?dev_key=" + DevKey + "&q=" + "geography";
Edit: Just thought of something else - try using List instead of Set[], maybe RestSharp will have an easier time with that.

Resources