我有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);
此行之后没有任何事情发生,这是该行的操作块。
那么有人能引导我吗?
答案 0 :(得分:1)
根据您的描述,您似乎可能想要这样的设置: 1)您的Windows窗体侦听串行端口 2)当新的东西到达端口时,你的Windows窗体应用程序将它保存到某种类型的队列(例如,msmq) 3)您应该有单独的Windows服务来检查队列,并且当它在队列中发现新消息时它向web api发送请求
答案 1 :(得分:1)
此问题的最佳解决方案是使用ConcurrentQueue。 只需在谷歌上进行搜索,你就可以得到样本。 ConcurrentQueue是线程安全的,它支持从多个线程写入和读取。 因此,侦听searal端口的组件可以将数据写入队列。并且您可以有两个或多个并行运行的任务,这些任务会在收到数据后立即监听此队列并更新数据库。
答案 2 :(得分:1)
不确定是否是问题,但您不应该阻止异步代码。你在做RunAsync(str).Wait();
,我相信这就是问题所在。看看Stephen Cleary撰写的这篇博客文章:
http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html
答案 3 :(得分:1)
通过独立我们在SO C#聊天室中确定你真正的意思是&#34;异步&#34;。
您的解决方案是上面的代码,将此数据保存到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部分:服务器部分
既然你有网络api我也会假设你也在使用EF,那么普通的&#34;清洁&#34;这样做的方式,所有额外的东西被剥离(如模型验证/错误处理)可能看起来像这样......
// 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,异步操作,流媒体。