【问题标题】:How to perform database operation independently?如何独立进行数据库操作?
【发布时间】:2016-04-21 03:38:53
【问题描述】:

我有1 exe,这与Windows form 没什么区别,它将在后台持续运行,并将watch my serial port,我有1 个事件data receive event which fires as my serial port receive data

一旦我收到此事件中的数据,我就会将此数据传递给另一个事件处理程序saves this data in database through web api method

但是到我的串口的数据会经常来,所以我想把这些数据独立保存到我的数据库中,这样我的数据库插入操作就不会阻塞我传入的串口数据。

这是我的代码:

void _serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)//Fires as my serial port receives data
{
    int dataLength = _serialPort.BytesToRead;
    byte[] data = new byte[dataLength];
    int nbrDataRead = _serialPort.Read(data, 0, dataLength);
    if (nbrDataRead == 0)
        return;

    // Send data to whom ever interested
    if (NewSerialDataRecieved != null)
    {
        NewSerialDataRecieved(this, new SerialDataEventArgs(data)); //pass serial port data to new below event handler.
    }
}


void _spManager_NewSerialDataRecieved(object sender, SerialDataEventArgs e) //I want this event handler to run independently so that database save operation doenst block incoming serial port data
{
    if (this.InvokeRequired)
    {
        // Using this.Invoke causes deadlock when closing serial port, and BeginInvoke is good practice anyway.
        this.BeginInvoke(new EventHandler<SerialDataEventArgs>(_spManager_NewSerialDataRecieved), new object[] { sender, e });
        return;
    }
    //data is converted to text
    string str = Encoding.ASCII.GetString(e.Data);

    if (!string.IsNullOrEmpty(str))
    {
            //This is where i will save data to through my web api method.
            RunAsync(str).Wait();
    }
}

static async Task RunAsync(string data)
{
    using (var client = new HttpClient())
    {
        client.BaseAddress = new Uri("http://localhost:33396/");
        client.DefaultRequestHeaders.Accept.Clear();
        client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        var content = new StringContent(data);
        var response = await client.PostAsJsonAsync<StringContent>("api/Service/Post", content);//nothing happens after this line.
    }
}

Web api 控制器:

public class MyController : ApiController
{
    [HttpPost]
    public HttpResponseMessage Post(HttpRequestMessage request)
    {
        var someText = request.Content.ReadAsStringAsync().Result;
        return new HttpResponseMessage() { Content = new StringContent(someText) };
    }
}

但这里的问题是:

var response = await client.PostAsJsonAsync<StringContent>("api/Service/Post", content);

在此行之后没有任何事情发生,即该行上的操作块。

那么有人可以指导我吗?

【问题讨论】:

  • 好的,我可以看到您再次开始使用该网站的问答进行提问,而不是通过同时与多人进行个人聊天来进行投票。
  • @Ian:有什么帮助或建议吗??
  • 您可能有一个后台线程来执行此操作。当您从串行端口接收数据时,您将其放入 QueueListStack - 任何适合您需要的集合类型,并且您还有 background thread 用于检查该项目是否存在定期收集。您使用此线程独立存储到数据库。
  • @Ian:任何例子或任何参考,我可以从哪里得到这个,或者如果你能发布代码会更好
  • 没有任何适合您的特殊情况。但是如果你一点一点地搜索,我想你应该通过一个一个地查看关键字来找到人们通常是怎么做的:后台线程、队列、堆栈等......

标签: c# winforms asynchronous asp.net-web-api serial-port


【解决方案1】:

我们在 SO C# 聊天室中独立确定您的真正意思是“异步”。

您的解决方案是上面的代码,将这些数据保存到 WebAPI 端点,因此任何问题的解决方案都需要分为两部分...

第 1 部分:客户端部分

在客户端,我们需要做的就是异步调用,以便释放当前线程继续在传入的串口上接收数据,我们可以这样做......

// build the api client, you may want to keep this in a higher scope to avoid recreating on each message
var api = new HttpClient();
api.BaseAddress = new Uri(someConfigVariable);

// asynchronously make the call and handle the result
api.PostAsJsonAsync("api/My", str)
    .ContinueWith(t => HandleResponseAsync(t.Result))
    .Unwrap();

...

第 2 部分:服务器部分

由于您有 web api,我还假设您也在使用 EF,执行此操作的常见且“干净”的方式,去除所有额外内容(如模型验证/错误处理)可能看起来像这……

// in your EF code you will have something like this ...
Public async Task<User> SaveUser(User userModel)
{
   try
  {
      var newUser = await context.Users.AddAsync(userModel);
      context.SavechangesAsync();
      return newUser;
  }
  catch(Exception ex) {}
}

// and in your WebAPI controller something like this ...

HttpPost]
public async Task<HttpResponseMessage> Post(User newUser)
{
     return Ok(await SaveUser(newUser));
}

...

免责声明:

这里涉及的概念更深入,正如我上面所暗示的,这里遗漏了很多东西,比如验证、错误检查等,但这是使用我相信你的技术将串行端口数据输入数据库的核心正在使用。

任何想要实现此类目标的人都需要阅读的关键内容可能包括:任务、事件处理、WebAPI、EF、异步操作、流式传输。

【讨论】:

  • 你的代码会有细微的变化。首先没有这样的方法:AddAsync,其次等待会出现,等待会伴随 SavechangesAsync
【解决方案2】:

根据您的描述,您可能想要这样的设置: 1)您的 Windows 窗体侦听串行端口 2)当新的东西来移植你的Windows窗体应用程序将它保存到某种队列(例如msmq) 3) 你应该有单独的 Windows 服务来检查队列,当它在队列中发现新消息时,它会向 web api 发送请求

【讨论】:

  • 你是对的,但是我应该去 Windows 服务还是后台线程来完成这项工作??
  • 嗯,这在很大程度上取决于你。你有几个选择,用户 Ian 已经提到了一些。您绝对可以在 Windows 窗体应用程序的后台线程中执行此操作,但话又说回来,您将数据库紧密耦合到 Windows 窗体应用程序生命周期/崩溃/错误/等。同样,这对您来说可能不是问题,但它是一个需要考虑的概念。另一方面,您可以不使用显式后台线程,而是使用任务并行库和异步数据库保存。如果我是你,我会选择 Windows 服务和某种队列。
  • 您的 NewSerialDataRecieved 事件处理程序不是异步的市场 + 您有 runasasync.wait() 这使它等待/阻止调用者。如果您希望它真正异步,则需要一直保持 async/await。
  • 好的,根据您的建议,我将使用窗口服务,但我应该使用队列或 BlockingCollection 根据这个问题:stackoverflow.com/questions/22839461/…
  • 暂时将 Windows 服务放在一边。请阅读我上面关于异步/等待的评论。一旦你解决了这个问题,你就可以进入下一步,将 db save 与 windows 窗体应用程序解耦。
【解决方案3】:

这个问题的最佳解决方案是使用 ConcurrentQueue。 只需在谷歌上搜索,您就会获得大量样品。 ConcurrentQueue 是线程安全的,它支持从多个线程写入和读取。 所以监听 searal 端口的组件可以将数据写入队列。并且您可以让 2 个或更多任务并行运行,这些任务会侦听此队列并在收到数据后立即更新数据库。

【讨论】:

【解决方案4】:

不确定是否是问题所在,但您不应该阻塞异步代码。你正在做RunAsync(str).Wait();,我相信这就是问题所在。看看 Stephen Cleary 的这篇博文: http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html

【讨论】:

    猜你喜欢
    • 2013-08-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-03
    • 2021-11-14
    • 1970-01-01
    • 2011-07-31
    相关资源
    最近更新 更多