如何独立进行数据库操作?
How to perform database operation independently?
我有 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);
这一行之后没有任何反应,因为这行是操作块。
那么有人可以指导我吗?
根据您的描述,您可能想要这样的设置:
1) 你的 windows 表单监听串口
2) 当新东西出现时,您的 windows 表单应用程序会将其保存到某种队列(例如,msmq)
3) 你应该有单独的 windows 服务来检查队列,当它在队列中找到新消息时它会向网络发送请求 api
此问题的最佳解决方案是使用 ConcurrentQueue。
只需在 google 上搜索,您就会得到大量样本。
ConcurrentQueue 是线程安全的,它支持从多个线程写入和读取。
这样监听seal端口的组件就可以向队列中写入数据了。您可以有 2 个或更多任务 运行 并行侦听此队列并在收到数据后立即更新数据库。
不确定这是否是问题所在,但您不应阻塞异步代码。您正在做 RunAsync(str).Wait();
,我相信这就是问题所在。看看 Stephen Cleary 的博客 post:
http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html
我们在 SO C# 聊天室中独立确定您的意思 "Asynchronously"。
您的解决方案是上面的代码,将此数据保存到 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,常见的 "clean" 方式来做到这一点,所有额外的东西都被剥离(比如模型验证/错误处理)可能看起来像这样...
// 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、异步操作、流。
我有 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);
这一行之后没有任何反应,因为这行是操作块。
那么有人可以指导我吗?
根据您的描述,您可能想要这样的设置: 1) 你的 windows 表单监听串口 2) 当新东西出现时,您的 windows 表单应用程序会将其保存到某种队列(例如,msmq) 3) 你应该有单独的 windows 服务来检查队列,当它在队列中找到新消息时它会向网络发送请求 api
此问题的最佳解决方案是使用 ConcurrentQueue。 只需在 google 上搜索,您就会得到大量样本。 ConcurrentQueue 是线程安全的,它支持从多个线程写入和读取。 这样监听seal端口的组件就可以向队列中写入数据了。您可以有 2 个或更多任务 运行 并行侦听此队列并在收到数据后立即更新数据库。
不确定这是否是问题所在,但您不应阻塞异步代码。您正在做 RunAsync(str).Wait();
,我相信这就是问题所在。看看 Stephen Cleary 的博客 post:
http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html
我们在 SO C# 聊天室中独立确定您的意思 "Asynchronously"。
您的解决方案是上面的代码,将此数据保存到 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,常见的 "clean" 方式来做到这一点,所有额外的东西都被剥离(比如模型验证/错误处理)可能看起来像这样...
// 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、异步操作、流。