- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我有一个 ASP.Net Core 2 Web 应用程序。
我正在尝试创建一个自定义路由中间件,这样我就可以从数据库中获取路由。
在 ConfigureServices()
我有:
services.AddDbContext<DbContext>(options =>
options.UseMySQL(configuration.GetConnectionString("ConnectionClient")));
services.AddScoped<IServiceConfig, ServiceConfig>();
在 Configure()
中:
app.UseMvc(routes =>
{
routes.Routes.Add(new RouteCustom(routes.DefaultHandler);
routes.MapRoute(name: "default", template: "{controller=Home}/{action=Index}/{id?}");
});
在RouteCustom
public class RouteCustom : IRouteCustom
{
private readonly IRouter _innerRouter;
private IServiceConfig _serviceConfig;
public RouteCustom(IRouter innerRouter)
{
_innerRouter = innerRouter ?? throw new ArgumentNullException(nameof(innerRouter));
}
public async Task RouteAsync(RouteContext context)
{
_serviceConfig = context.HttpContext
.RequestServices.GetRequiredService<IServiceConfig>();
/// ...
// Operations inside _serviceConfig to get the route
}
public VirtualPathData GetVirtualPath(VirtualPathContext context)
{
_serviceConfig = context.HttpContext
.RequestServices.GetRequiredService<IServiceConfig>();
// ...
// Operations inside _serviceConfig to get the route
}
}
IServiceConfig
它只是一个类,我在其中访问数据库以获取数据,在本例中为路由,还有应用程序所需的其他配置数据。
public interface IServiceConfig
{
Config GetConfig();
List<RouteWeb> SelRoutesWeb();
}
public class ServiceConfig : IServiceConfig
{
private readonly IMemoryCache _memoryCache;
private readonly IUnitOfWork _unitOfWork;
private readonly IServiceTenant _serviceTenant;
public ServiceConfig(IMemoryCache memoryCache,
IUnitOfWork unitOfWork,
IServiceTenant serviceTenant)
{
_memoryCache = memoryCache;
_unitOfWork = unitOfWork;
_serviceTenant = serviceTenant;
}
public Config GetConfig()
{
var cacheConfigTenant = Names.CacheConfig + _serviceTenant.GetId();
var config = _memoryCache.Get<Config>(cacheConfigTenant);
if (config != null)
return config;
config = _unitOfWork.Config.Get();
_memoryCache.Set(cacheConfigTenant, config,
new MemoryCacheEntryOptions()
{
SlidingExpiration = Names.CacheExpiration
});
return config;
}
public List<RouteWeb> SelRoutesWeb()
{
var cacheRoutesWebTenant = Names.CacheRoutesWeb + _serviceTenant.GetId();
var routesWebList = _memoryCache.Get<List<RouteWeb>>(cacheRoutesWebTenant);
if (routesWebList != null)
return routesWebList;
routesWebList = _unitOfWork.PageWeb.SelRoutesWeb();
_memoryCache.Set(cacheRoutesWebTenant, routesWebList,
new MemoryCacheEntryOptions()
{
SlidingExpiration = Names.CacheExpiration
});
return routesWebList;
}
}
问题是我在打开多个选项卡进行测试并尝试同时刷新所有选项卡时收到此消息:“在前一个操作完成之前,第二个操作在此上下文中开始”
我确定我做错了什么,但我不知道是什么。它必须是访问自定义路由中间件内的数据库的更好方法,甚至是更好的方法。
例如,在常规中间件(不是路由中间件)上,我可以将依赖项注入(inject) Invoke 函数,但我不能在此处将依赖项注入(inject) RouteAsync 或 GetVirtualPath()
。
这里会发生什么?
提前致谢。
更新这些是我遇到的异常。
An unhandled exception occurred while processing the request.InvalidOperationException: A second operation started on this context before a previous operation completed. Any instance members are not guaranteed to be thread safe.
还有这个:
An unhandled exception occurred while processing the request.MySqlException: There is already an open DataReader associated with this Connection which must be closed first.
这是工作单元
public interface IUnitOfWork : IDisposable
{
ICompanyRepository Company { get; }
IConfigRepository Config { get; }
// ...
void Complete();
}
public class UnitOfWork : IUnitOfWork
{
private readonly DbContext _context;
public UnitOfWork(DbContext context)
{
_context = context;
Company = new CompanyRepository(_context);
Config = new ConfigRepository(_context);
// ...
}
public ICompanyRepository Company { get; private set; }
public IConfigRepository Config { get; private set; }
// ...
public void Complete()
{
_context.SaveChanges();
}
public void Dispose()
{
_context.Dispose();
}
}
更新 2
在查看评论并进行大量测试后,我得到的最好线索是当我删除 CustomRoute 行时问题就消失了。从 Startup.cs 的 Configure 函数中删除这一行
routes.Routes.Add(new RouteCustom(routes.DefaultHandler));
我也曾尝试删除,首先是 RouteAsync,然后是 GetVirtualPath()
方法,但如果存在其中一个方法,我会得到一个错误,所以很明显问题出在这个 CustomRoute
类。
在 TenantMiddleware
(对于任何请求都会首先调用)中,我正在注入(inject) UnitOfWork,我没有遇到任何问题。这个中间件是在 Configure 函数中创建的:
app.UseMiddleware<TenantMiddleware>();
在内部,我正在注入(inject) UnitOfWork,并在每次请求时使用它,如下所示:
public async Task Invoke(HttpContext httpContext, IServiceTenant serviceTenant)
{
// ...performing DB operations to retrieve the tenent's data.
}
public class ServiceTenant : IServiceTenant
{
public ServiceTenant(IHttpContextAccessor contextAccessor,
IMemoryCache memoryCache,
IUnitOfWorkMaster unitOfWorkMaster)
{
_unitOfWorkMaster = unitOfWorkMaster;
}
// ...performing DB operations
}
所以,CustomRoute
的问题是我无法通过像这样添加到 Invoke 函数来注入(inject)依赖项:
public async Task Invoke(HttpContext httpContext, IServiceTenant serviceTenant)
所以我必须像这样调用相应的服务(在该服务中我注入(inject) UnitOfWork 并执行数据库操作),我认为这可能是导致问题的原因:
public async Task RouteAsync(RouteContext context)
{
_serviceConfig = context.HttpContext
.RequestServices.GetRequiredService<IServiceConfig>();
// ....
}
因为这是我知道的将 IServiceConfig
“注入(inject)”到 RouteAsync 和 GetVirtualPath()
中的唯一方法...
此外,由于我使用的是 BaseCOntroller,所以我在每个 Controller 中都这样做,所以我决定我使用哪个操作系统的注入(inject)服务...
public class BaseWebController : Controller
{
private readonly IMemoryCache _memoryCache;
private readonly IUnitOfWork _unitOfWork;
private readonly IUnitOfWorkMaster _unitOfWorkMaster;
private readonly IServiceConfig _serviceConfig;
private readonly IServiceFiles _serviceFiles;
private readonly IServiceFilesData _serviceFilesData;
private readonly IServiceTenant _serviceTenant;
public BaseWebController(IServiceProvider serviceProvider)
{
_memoryCache = serviceProvider.GetRequiredService<IMemoryCache>();
_unitOfWork = serviceProvider.GetRequiredService<IUnitOfWork>();
_unitOfWorkMaster = serviceProvider.GetRequiredService<IUnitOfWorkMaster>();
_serviceConfig = serviceProvider.GetRequiredService<IServiceConfig>();
_serviceFiles = serviceProvider.GetRequiredService<IServiceFiles>();
_serviceFilesData = serviceProvider.GetRequiredService<IServiceFilesData>();
_serviceTenant = serviceProvider.GetRequiredService<IServiceTenant>();
}
}
然后在每个 Controller 中,无需引用所有注入(inject)的服务,我可以只为我需要的服务执行此操作,如下所示:
public class HomeController : BaseWebController
{
private readonly IUnitOfWork _unitOfWork;
public HomeController(IServiceProvider serviceProvider) : base(serviceProvider)
{
_unitOfWork = serviceProvider.GetRequiredService<IUnitOfWork>();
}
public IActionResult Index()
{
// ...
}
}
我不知道这是否与我的问题有关,但我只是向您展示了我认为可能的问题所在,以便您获得更多信息。
谢谢。
更新 3
这是检索路由的数据库代码:
public class PageWebRepository : Repository<PageWeb>, IPageWebRepository
{
public PageWebRepository(DbContext context) : base(context) { }
public List<RouteWeb> SelRoutesWeb()
{
return Context.PagesWebTrs
.Include(p => p.PageWeb)
.Where(p => p.PageWeb.Active)
.Select(p => new RouteWeb
{
PageWebId = p.PageWebId,
LanguageCode = p.LanguageCode,
Route = p.Route,
Regex = p.PageWeb.Regex.Replace("<route>", p.Route),
Params = p.PageWeb.Params,
Area = p.PageWeb.Area,
Controller = p.PageWeb.Controller,
Action = p.PageWeb.Action,
Type = p.PageWeb.Type,
Sidebar = p.PageWeb.Sidebar,
BannerIsScript = p.PageWeb.BannerIsScript,
Title = p.Title,
Description = p.Description,
Keywords = p.Keywords,
ScriptHead = p.ScriptHead,
ScriptBody = p.ScriptBody,
BannerScript = p.BannerScript,
BannerUrl = p.BannerUrl,
})
.ToList();
}
}
其中 PagesWebTrs 是页面的翻译(多语言),PagesWeb 是主表。
最佳答案
这个问题确实在路由中间件中。
根据定义,中间件是单例,因此单个实例处理所有请求。这导致实例状态(IServiceConfig
与 DbContext
Hook )被多个同时请求访问和更改;这是一个伪装得很好的经典并发问题。
一个例子。
请求 A 执行 RouteAsync
,设置 _serviceConfig
并在 DbContext
上执行查询。纳秒(或更少 :))之后,请求 B 执行相同的操作。在执行请求 B 的查询时,请求 A 执行 GetVirtualPath
,但这次是在请求 B 设置的 DbContext
上执行。这导致在 上执行第二个查询请求 B 的 >DbContext
仍然有一个正在运行,你得到了提到的错误。
解决方案是通过在每个方法开始时检索 IServiceConfig
来防止共享状态。
如您所说,通过 Invoke
方法注入(inject)这样的依赖项是行不通的; Invoke
方法没有被执行。
下面是修改后的 RouteCustom
。
public class RouteCustom : IRouteCustom
{
private readonly IRouter _innerRouter;
public RouteCustom(IRouter innerRouter)
{
_innerRouter = innerRouter ?? throw new ArgumentNullException(nameof(innerRouter));
}
public async Task RouteAsync(RouteContext context)
{
var serviceConfig = context.HttpContext.RequestServices.GetRequiredService<IServiceConfig>();
// ...
}
public VirtualPathData GetVirtualPath(VirtualPathContext context)
{
var serviceConfig = context.HttpContext.RequestServices.GetRequiredService<IServiceConfig>();
// ...
}
}
关于c# - asp.net core 在上一个操作完成之前在此上下文中开始第二个操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50565991/
我试图对 ASP.Net MVC 有一个高层次的理解,我开始意识到它看起来很像原始的 ASP 脚本。过去,我们将“模型”/业务逻辑代码组织到 VBScript 类或 VB COM 组件中。 当然,现在
我已经搜索了一段时间,但似乎找不到答案。 我想在我的旋转木马中显示一个计数器,左边是当前项目(工作),左边是项目总数。 我的代码:
. 最佳答案 Scott Gu 称这些为代码块。这就是我的看法。 http://weblogs.asp.net/scottgu/archive/2010/04/06/new-lt-gt-syntax
我有一个使用 Visual Studio 2010/.net 4/VB 制作的网站。 我真的很喜欢我发现的 FAQ 系统的布局,因为它很简单,但它是经典的 asp。所以,显然,我不能包括我的母版页布局
好吧,对于你们许多人来说,这个问题可能有一个非常明显的答案,但它让我难住了。 我有一个 asp.net Web 表单,上面有两个控件(嗯,不止这两个,但我们将重点关注这些) - 第一个是 asp:dr
当我将 ASP.NET 复选框控件设置为 asp.net 更新面板的异步回发触发器时,EventName 属性是什么? 最佳答案 我相信它是 CheckedChanged。 关于asp.net - a
我有一个用经典 asp 编写的(巨大的)网站。现在我必须切换到 vb.net (razor)。有没有办法将这两个结合起来直到切换完成? 有没有办法让应用程序与经典的 asp 和 vb.net 一起工作
I am creating a products page, where the user selects an option in a radiobuttonlist for example, an
我最近将一个经典的 ASP 应用程序转换为 ASP.NET 3.5,但我觉得我的经典 ASP 版本要快一些(我不知道可能买家会后悔)。 所以你们能帮我解决这个问题吗,让我知道哪个更快,asp、asp.
从本周开始,我被要求开始学习如何使用 ASP 开发网站。我通过 XNA 对 C# 有一定的经验,所以这部分对我来说并不是什么麻烦。 我一直在关注Music Store Tutorial这需要我设置一个
关闭。这个问题需要多问focused 。目前不接受答案。 想要改进此问题吗?更新问题,使其仅关注一个问题 editing this post . 已关闭 8 年前。 Improve this ques
我想将一些表单变量发布到经典 ASP 页面中。我不想改变经典的 ASP 页面,因为需要完成大量的工作,以及消耗它们的页面数量。 经典的 ASP 页面需要将表单变量 Username 和 Userpas
已结束。此问题正在寻求书籍、工具、软件库等的推荐。它不满足Stack Overflow guidelines 。目前不接受答案。 我们不允许提出寻求书籍、工具、软件库等推荐的问题。您可以编辑问题,以便
在某种程度上,这可能是一个异端问题。我们有一个大型站点,其中许多页面仍在ASP中。通常,并没有真正动态的,而是包括(通过SSI或Server.Execute)定期重新生成的HTML块。看起来好像是一个
关闭。这个问题需要多问focused 。目前不接受答案。 想要改进此问题吗?更新问题,使其仅关注一个问题 editing this post . 已关闭 9 年前。 Improve this ques
我有一个遗留的 ASP 应用程序——在不久的某个时候——需要迁移到 ASP.Net 2.0(以与也在 2.0 中的其他应用程序兼容)。 对于这类事情是否有最佳实践,即作为第一步将当前 html、vbs
我目前在一家公司工作,该公司使用 ASP.NET Webforms 和旧 ASP 页面的组合进行 Web 开发。这对于他们当前的项目来说效果很好,但我想说服/建议他们切换到 ASP.NET MVC,因
我有一个经典的 asp 应用程序。我想将该页面的竞赛表格发布到 Asp.Net 表格。原因是我想在进入数据库之前使用我在 Asp.Net 页面中内置的大量逻辑进行验证,而我对 asp 不太了解。更不用
我知道在 ASP.NET MVC 中,您可以拥有移动 View 并执行类似 Index.mobile.cshtml 的操作。和 _Layout.mobile.cshtml并且服务器知道将这些 View
我需要从一些服务器端 c#.net 代码中调用经典 asp 页面上的 VBscript 函数 - 有谁知道一种干净的方法来做到这一点?在 .net 中重写函数不是一种选择。 我会再解释一下这个问题..
我是一名优秀的程序员,十分优秀!