我公司的一位测试人员在我的ASP.Net MVC 3解决方案上发现了一个错误,我相信这很常见。
它可以处理的服务器的一个帖子。但是,如果您发送了大量帖子,例如拒绝服务攻击(DoS攻击),则会抛出异常:
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
如下所述:
多次点击按钮。或者单击一次并按Enter键,它会向服务器发送大量请求“发布”。
模型基本上是:
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; }
}
控制器:
[HttpPost]
public JsonResult SaveOrUpdateOrderLines( CustomerOrderModel customerOrderModel)
{
if (customerOrderModel.CustomerOrderHeader.OrderNumber == 0)
{
customerOrderModel.CustomerOrderHeader.OrderNumber = this.CustomerOrderService.CreateOrUpdate(customerOrderHeader, false);
}
返回 JSON( 新 { OrderNumber = customerOrderModel.CustomerOrderHeader.OrderNumber, CustomerOrderLines = new { CustomerOrderLine =( 来自custOrderHeader.CustomerOrderLines中的ordeline 选择新的 { Id = ordeline.Id, LineNumber = ordeline.LineNumber, LineStatus = ordeline.LineStatus }
).ToArray()
}
},
JsonRequestBehavior.AllowGet
);
}
CustomerOrder服务:
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;
}
}
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;
}
}
答案 0 :(得分:1)
增加连接池限制可以帮助延长它的持续时间,只要您不会使服务器/网络饱和太多。
尽可能晚和早(分别)打开和关闭数据库连接。您可能希望将会话从每个请求(或您正在使用的任何内容)打开/关闭切换为正在使用。
在您的情况下,由于它是界面上的一个按钮,您可以暂时禁用它(使用JavaScript)一段时间,这样用户就无法以更快的速度点击它。
无论如何,您应该在网络或IIS级别对传入请求进行速率限制。
答案 1 :(得分:0)
确保您没有跨多个NHibernate会话共享对象。
如果会话#1加载会话#2尝试提交的对象,则可能发生该错误。