锁定Web API控制器方法

2024-03-01

我正在使用 C# 和 .Net Framework 4.7 开发 ASP.NET Web Api 应用程序。

我在控制器中有一种方法,我只想一次仅由一个线程执行。换句话说,如果有人调用此方法,则另一个调用必须等待该方法完成。

我找到了这个所以答案 https://stackoverflow.com/a/42117694/68571那可以完成这项工作。但这里它使用一个队列,我不知道如何使用该队列。在该答案中解释说,我可以创建一个 Windows 服务来使用队列,但我不想在我的解决方案中添加另一个应用程序。

我想在 Web Api 方法中添加一个锁,如下所示:

[HttpPut]
[Route("api/Public/SendCommissioning/{serial}/{withChildren}")]
public HttpResponseMessage SendCommissioning(string serial, bool withChildren)
{
    lock
    {
        string errorMsg = "Cannot set commissioning.";

        HttpResponseMessage response = null;
        bool serverFound = true;

        try
        {
            [ ... ]
        }
        catch (Exception ex)
        {
            _log.Error(ex.Message);

            response = Request.CreateResponse(HttpStatusCode.InternalServerError);
            response.ReasonPhrase = errorMsg;
        }

        return response;
    }
}

但我不认为这是一个好的解决方案,因为如果运行该方法出现问题,它可能会阻止大量待处理的调用,并且我将丢失所有待处理的调用,或者也许我错了,调用(线程)将等待直到其他结束。换句话说,我认为如果我使用 this 我可能会陷入僵局。

我正在尝试这样做,因为我需要按照收到的顺序执行调用。查看此操作日志:

2017-06-20 09:17:43,306 DEBUG [12] WebsiteAction - ENTERING PublicController::SendCommissioning , serial : 38441110778119919475, withChildren : False
2017-06-20 09:17:43,494 DEBUG [13] WebsiteAction - ENTERING PublicController::SendCommissioning , serial : 38561140779115949572, withChildren : False
2017-06-20 09:17:43,683 DEBUG [5] WebsiteAction - ENTERING PublicController::SendCommissioning , serial : 38551180775118959070, withChildren : False
2017-06-20 09:17:43,700 DEBUG [12] WebsiteAction - EXITING PublicController::SendCommissioning 
2017-06-20 09:17:43,722 DEBUG [5] WebsiteAction - EXITING PublicController::SendCommissioning 
2017-06-20 09:17:43,741 DEBUG [13] WebsiteAction - EXITING PublicController::SendCommissioning 

在其中任何一个结束之前我收到三个电话:线程[12], [13] and [5]. But 最后一个在第二个之前结束: [12], [5] and [13].

我需要一种机制来不允许这种情况发生。

我该如何确保呼叫按照我拨打的顺序进行处理?


您的锁解决方案应该可以正常工作。如果请求失败,那么锁将被释放,其他待处理的请求可以进入该锁。不会出现死锁。

此解决方案的唯一问题是 Web 请求可能会持续挂起很长一段时间(这可能会导致客户端超时)。

public class MyApi : ApiController
{
    public static readonly object LockObject = new object();

    [HttpPut]
    [Route("api/Public/SendCommissioning/{serial}/{withChildren}")]
    public HttpResponseMessage SendCommissioning(string serial, bool withChildren)
    {
        lock ( LockObject )
        {
            //Do stuff
        }
    }
}

要解决挂起请求的问题,您应该使用队列,并轮询后端(或者如果您喜欢,可以尝试 SignalR),直到您的工作完成。例如:

//This is a sample with Request/Result classes (Simply implement as you see fit)
public static class MyBackgroundWorker
{
    private static ConcurrentQueue<KeyValuePair<Guid, Request>> _queue = new ConcurrentQueue<KeyValuePair<Guid, Result>>()
    public static ConcurrentDictionary<Guid, Result> Results = new ConcurrentDictionary<Guid, Result>();

    static MyBackgroundWorker()
    {
         var thread = new Thread(ProcessQueue);
         thread.Start();
    }

    private static void ProcessQueue()
    {
         KeyValuePair<Guid, Request> req;
         while(_queue.TryDequeue(out req))
         {
             //Do processing here (Make sure to do it in a try/catch block)
             Results.TryAdd(req.Key, result);
         }
    }

    public static Guid AddItem(Request req)
    {
        var guid = new Guid();
        _queue.Enqueue(new KeyValuePair(guid, req));
        return guid;
    }
}


public class MyApi : ApiController
{
    [HttpPut]
    [Route("api/Public/SendCommissioning/{serial}/{withChildren}")]
    public HttpResponseMessage SendCommissioning(string serial, bool withChildren)
    {
        var guid = MyBackgroundWorker.AddItem(new Request(serial, withChildren));
        return guid;
    }

    [HttpGet]
    [Route("api/Public/GetCommissioning/{guid}")]
    public HttpResponseMessage GetCommissioning(string guid)
    {
        if ( MyBackgroundWorker.Results.TryRemove(new Guid(guid), out Result res) )
        {
            return res;
        }
        else
        {
            //Return result not done
        }
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

锁定Web API控制器方法 的相关文章

  • Accept() 是线程安全的吗?

    我目前正在用 C 语言为我正在做的课程编写一个简单的网络服务器 我们的一项要求是实现一个线程池来使用 pthread 处理连接 我知道我将如何粗略地执行此操作 在主线程中调用accept并将文件描述符传递给freee线程 但是我的朋友建议了
  • 获取 std::variant 当前持有的 typeid(如 boost::variant type())

    我已经从 boost variant 迁移到 std variant 但遇到了障碍 我在 boost type 中使用了一个很好的函数 它可以让你获取当前持有的 typeid 看https www boost org doc libs 1
  • 如何使用 MVVM 更新 WPF 中编辑的数据? [复制]

    这个问题在这里已经有答案了 我正在为聊天应用程序构建 UI 设计 在尝试更新所选联系人的消息时遇到问题 选择现有联系人 选择编辑选项 然后编辑其属性 例如用户名和图像 后 唯一进行的更改是联系人的用户名和图像 我仍然想更改 MessageM
  • 键盘加速器在 UWP 应用中停止工作

    我正在尝试将键盘加速器添加到 UWP 应用程序中的 CommandBar 菜单项 当应用程序启动时 这工作正常 但在我第一次打开溢出菜单后 加速器停止工作 这似乎不会发生在主要命令 菜单之外 上 只有溢出菜单内的辅助命令才会发生 此外 单击
  • 是否允许将类模板类型参数键入相同的名称?

    这似乎可以在 MSVC 中按预期编译甚至工作 但它是合法的 C 代码吗 它是否能保证执行此处所期望的操作 即将模板类型导出到结构体的同名用户 template
  • C# 中四舍五入到偶数

    我没有看到 Math Round 的预期结果 return Math Round 99 96535789 2 MidpointRounding ToEven returning 99 97 据我了解 MidpointRounding ToE
  • 用户控件内所有控件均为空

    我有一个 UserControl 它使用 UserControl 以及其他控件 In the ascx文件我有以下代码
  • 为什么这个函数指针赋值在直接赋值时有效,但在使用条件运算符时无效?

    本示例未使用 include 在 MacOS10 14 Eclipse IDE 上编译 使用 g 选项 O0 g3 Wall c fmessage length 0 假设这个变量声明 int fun int 这无法通过 std touppe
  • 导出类时编译器错误

    我正在使用 Visual Studio 2013 但遇到了一个奇怪的问题 当我导出一个类时 它会抛出 尝试引用已删除的函数 错误 但是 当该类未导出时 它的行为会正确 让我举个例子 class Foo note the export cla
  • Qt 计算和比较密码哈希

    目前正在 Qt 中为测验程序构建面向 Web 的身份验证服务 据我了解 在数据库中存储用户密码时 必须对其进行隐藏 以防落入坏人之手 流行的方法似乎是添加的过程Salt https en wikipedia org wiki Salt cr
  • 是否有像 gccxml 这样的用于生成包装器的 C 标头解析器工具?

    我需要为一种新的编程语言编写一些 C 标头包装器 并且想要类似 gccxml 的东西 但不完全依赖 gcc 以及它在 Windows 系统上带来的问题 只需要读C而不是C 只要有完整的文档记录 任何格式的输出都可以 Linux Solari
  • 单线程公寓问题

    从我的主窗体中 我调用以下命令来打开一个新窗体 MyForm sth new MyForm sth show 一切都很好 但是这个表单有一个组合框 当我将其 AutoCompleteMode 切换为建议和追加时 我在显示表单时遇到了这个异常
  • 指向字节数组的指针

    由于 Misra C 的要求 我的一位同事想要使用指针声明 但我遇到了一些问题 Misra 安全关键指南 不会让我们纯粹的程序员使用指针 但会让我们对数组字节进行操作 他打算获取一个指向字节数组的指针 因此我们不会在堆栈上传递实际的数组 T
  • 以编程方式更新 ClickOnce 应用程序的部署清单会导致缺少 4.0 中所需的 <兼容框架> 元素

    我正在致力于自动化 NET 4 0 ClickOnce WPF 应用程序的安装程序 该应用程序需要在应用程序配置文件 我经历了寻找必须遵循的具体步骤的棘手过程Mage exe http msdn microsoft com en us li
  • 如何用 C 语言练习 Unix 编程?

    经过五年的专业 Java 以及较小程度上的 Python 编程并慢慢感觉到我的计算机科学教育逐渐消失 我决定要拓宽我的视野 对世界的一般用处 并做一些 对我来说 感觉更重要的事情就像我真的对机器有影响一样 我选择学习 C 和 Unix 编程
  • 将非算术类型作为参数传递给 cmath 函数是否有效?

    给定以下用户定义类型S具有转换功能double struct S operator double return 1 0 以及以下调用cmath http en cppreference com w cpp header cmath使用类型的
  • 如何访问窗口?

    我正在尝试使用其句柄访问特定窗口 即System IntPtr value Getting the process of Visual Studio program var process Process GetProcessesByNam
  • 如何获取 QIcon 的文件/资源​​路径

    假设我做了这样的事情 QIcon myIcon resources icon ico 我稍后如何确定该图标的路径 例如 QString path myIcon getPath 问题是 没有getPath 会员 我找不到类似的东西 但肯定有办
  • 启动画面后主窗口出现在其他窗口后面

    我有一个带有启动屏幕的 Windows 窗体应用程序 当我运行该应用程序时 启动屏幕显示正常 消失并加载应用程序的主窗体 但是 当我加载主窗体时 它出现在包含该应用程序的 Windows 资源管理器目录下 这是运行启动画面然后运行主窗体的代
  • c# 模拟 IFormFile CopyToAsync() 方法

    我正在对一个异步函数进行单元测试 该函数将 IFormFile 列表转换为我自己的任意数据库文件类列表 将文件数据转换为字节数组的方法是 internal async Task

随机推荐

  • 检测滑动手势方向

    这是我尝试模拟滑动手势的代码 因此当我构建移动设备时 我知道它会起作用 没有记录任何内容 我很困惑为什么它似乎不起作用 我希望它在我滑动的控制台中打印出来RTL 从右到左 或LTR 左到右 我不明白我做错了什么 void Update if
  • 如何在 Sails.js 中压缩 JavaScript 和 CSS 资源?

    我正在尝试在 Sails js Node 应用程序中为我的资产启用 gzip 压缩 在生产环境中启动应用程序时 所有资产assets linker js and assets linker styles已成功连接 缩小 丑化 如 Grunt
  • 如何从 CLI 构建 DocC 文档

    所以我已经浏览网页有一段时间了 似乎找不到有关如何构建的答案本机 DocC Xcode 文档 使用 CLI 命令 这俩xcodebuild据我所知 commands 和 Fastlane 不提供构建文档的命令 应该构建文档CI CD Git
  • IllegalArgumentException:ID 未引用此 Activity 内的视图

    我一直在尝试为我的应用程序制作一个主页 其中包含一些现代仪表板和导航抽屉 在我的代码中发现错误 E AndroidRuntime FATAL EXCEPTION main Process com example thinkerlab PID
  • 在 MacOS 上使用 cx_freeze 打包 tkinter GUI 会导致黑色 GUI

    我正在构建一个tkinter一位朋友在运行 macOS Catalina 10 15 2 的 Mac 上使用 Python 3 8 3 的 GUI 并尝试使用冻结它cx freeze 6 1 当我在本地环境中运行 python 应用程序时
  • utf8数据在mysql中看起来很好,但在rails中被破坏了

    我正在为我的一位同事设置一个 Rails 环境 他使用的是 Mac 如果相关的话 我已经从我们的实时 mysql 数据库中提取了数据 并使用该数据创建了一个本地开发数据库 如果我打开 mysql 控制台 并查看其名称字段中具有扩展字符集字符
  • IntelliJ 中的 CLI-Spring Shell

    我正在 IntelliJ 中编写 CLI Spring shell 代码 我运行它并给出一些参数 但是当我输入 insert 并按 Enter 时 控制台不接受它 看起来好像什么也没发生 My code Component public c
  • 如何强制iFrame打开所有链接保留在iFrame中?

    我正在托管一个 iFrame 似乎当链接指向外部域时 它会将其加载到主窗口而不是 iFrame 中 有没有办法强制在同一个 iFrame 中打开链接 注意 我可以向 iFrame 中加载的页面添加任何我想要的内容 使用 Chrome 扩展
  • .NET MVC 3 自定义控制器属性

    这可能是天上掉馅饼 但我想知道是否可以使用自定义控制器属性来完成以下操作 对于大多数控制器 我将向控制器内的每个操作传递一个名为 r 的 URL 参数 r 与我的数据库中的竞赛表中的竞赛 ID 相关联 我希望发生的是 每当调用控制器操作时
  • 增加命中 S3 存储桶端点时允许的最大标头大小

    I am curl 重定向到 S3 存储桶的端点 我必须将一些大标头传递给我的请求 但由于超出了最大标头大小 该请求失败了
  • 使用纯 JavaScript 单击隐藏 Bootstrap 模态框

    我正在研究 Bootstrap Pop Up Modals 我有 2 个名为Button1 Button2 我有 2 个名为Modal1 Modal2 Note Button2是在里面Modal1 Button1在网页上 如果我点击Butt
  • 如何使用 Firebase 将初始数据加载与增量子项分开?

    我有一个应用程序 每 5 秒左右就会有新的子进程添加到 Firebase 中 我有成千上万的孩子 在应用程序加载时 我希望以不同于每 5 秒一次的后续子项的方式处理最初的数千个子项 您可能建议我使用值 处理所有内容 然后使用children
  • 自动装箱与静态数字

    有使用价值吗Integer i NumberUtils INTEGER ONE代替Integer i 1 我不知道自动拳击背后会发生什么 Thanks 基本上它会被编译成 Integer i Integer valueOf NumberUt
  • 将包含 JSON 对象的数据框扩展为更大的数据框

    我有一个带有两列的 pandas 数据框 一个是 ID 另一个是长 JSON 对象 对于数据帧中的每个对象来说都是相同的对象 我的目标是为 JSON 对象中的每个键创建列 这是输入的示例 ID request json 175431467
  • 如何在 5 分钟内使 Django 会话过期?

    我用它来登录用户 def login backend request if request method POST username request POST username password request POST password
  • 如何从表中的列中删除默认值?

    如何更改列以删除默认值 该列是通过以下内容创建的 ALTER table sometable Add somecolumn nchar 1 NOT NULL DEFAULT N 然后修改为 alter table sometable alt
  • 计算每个派生类的类实例

    有没有办法让所有派生类计算它们的实例 如何 用 C C Java 之一编写代码 想象一下 我可以访问根类 例如对象 并且每个其他类都是 直接或间接 从该类派生的 我想要的是 AnyDerivedClass InstancesCount 问题
  • 对象原型不“实时更新”

    我有以下代码 var Test function Test prototype doSomething function return done 现在 我创建一个 Test 对象 var t new Test alert t doSomet
  • 在虚拟环境中安装我自己的 python 模块

    我拥有的 我想要将其转换为模块的本地 Python3 文件test module test module包含空文件夹 init py a setup py文件 见下文 和具有多个源的子目录 文件 我想要的是 不断努力和改进test modu
  • 锁定Web API控制器方法

    我正在使用 C 和 Net Framework 4 7 开发 ASP NET Web Api 应用程序 我在控制器中有一种方法 我只想一次仅由一个线程执行 换句话说 如果有人调用此方法 则另一个调用必须等待该方法完成 我找到了这个所以答案