Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/296.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 来自SQLCLR的异步API调用中的问题_C#_.net_Sql Server_Async Await_Sqlclr - Fatal编程技术网

C# 来自SQLCLR的异步API调用中的问题

C# 来自SQLCLR的异步API调用中的问题,c#,.net,sql-server,async-await,sqlclr,C#,.net,Sql Server,Async Await,Sqlclr,简而言之,我需要在特定表中发生更改时从SQL Server异步通知Web API服务 为了实现上述目标,我创建了一个SQLCLR存储过程,其中包含通知服务的异步API调用。当在名为Table1的表中插入时,通过触发器调用SQLCLR存储过程。这里的主要挑战是API必须从同一个表中读取数据(Table1) 如果我使用同步版本的HttpWebRequest.GetResponse(),由于插入触发器的隐式锁,整个操作将被锁定。为了避免这种情况,我使用了HttpWebRequest.GetRespon

简而言之,我需要在特定表中发生更改时从SQL Server异步通知Web API服务

为了实现上述目标,我创建了一个SQLCLR存储过程,其中包含通知服务的异步API调用。当在名为
Table1
的表中插入时,通过触发器调用SQLCLR存储过程。这里的主要挑战是API必须从同一个表中读取数据(
Table1

如果我使用同步版本的
HttpWebRequest.GetResponse()
,由于插入触发器的隐式锁,整个操作将被锁定。为了避免这种情况,我使用了
HttpWebRequest.GetResponseAsync()
方法,该方法调用API并且不等待响应。因此,它触发API请求,程序控制继续,这样触发器事务就不会在
table1
上持有任何锁,并且API能够从
table1
读取数据

现在,当出现故障(如无法连接到远程服务器)时,我必须实现一个错误通知机制,并且我需要向管理团队发送电子邮件。我已经在
catch()
块中编写了邮件合成逻辑。如果继续上面的
HttpWebRequest.GetResponseAsync().Result
方法,整个操作将变得同步,并锁定整个操作

如果我使用Microsoft文档中建议的
BeginGetResponse()
EndGetResponse()
方法实现并运行SQLCLR存储过程,SQL Server会在没有任何信息的情况下挂起,为什么?我做错了什么?为什么不执行
RespCallback()
方法

共享下面的SQLCLR代码段

public class RequestState
{
    // This class stores the State of the request.
    // const int BUFFER_SIZE = 1024;
    // public StringBuilder requestData;
    // public byte[] BufferRead;
    public HttpWebRequest request;
    public HttpWebResponse response;
    // public Stream streamResponse;

    public RequestState()
    {
        // BufferRead = new byte[BUFFER_SIZE];
        // requestData = new StringBuilder("");
        request = null;
        // streamResponse = null;
    }
}

public partial class StoredProcedures
{
    private static SqlString _mailServer = null;
    private static SqlString _port = null;
    private static SqlString _fromAddress = null;
    private static SqlString _toAddress = null;
    private static SqlString _mailAcctUserName = null;
    private static SqlString _decryptedPassword = null;
    private static SqlString _subject = null;

    private static string _mailContent = null;
    private static int _portNo = 0;

    public static ManualResetEvent allDone = new ManualResetEvent(false);
    const int DefaultTimeout = 20000; // 50 seconds timeout

#region TimeOutCallBack
/// <summary>
/// Abort the request if the timer fires.
/// </summary>
/// <param name="state">request state</param>
/// <param name="timedOut">timeout status</param>
private static void TimeoutCallback(object state, bool timedOut)
{
if (timedOut)
{
HttpWebRequest request = state as HttpWebRequest;
if (request != null)
{
request.Abort();
SendNotifyErrorEmail(null, "The request got timedOut!,please check the API");
}
}
}
#endregion

#region APINotification
[SqlProcedure]
public static void Notify(SqlString weburl, SqlString username, SqlString password, SqlString connectionLimit, SqlString mailServer, SqlString port, SqlString fromAddress
, SqlString toAddress, SqlString mailAcctUserName, SqlString mailAcctPassword, SqlString subject)
{
_mailServer = mailServer;
_port = port;
_fromAddress = fromAddress;
_toAddress = toAddress;
_mailAcctUserName = mailAcctUserName;
_decryptedPassword = mailAcctPassword;
_subject = subject;

if (!(weburl.IsNull && username.IsNull && password.IsNull && connectionLimit.IsNull))
{
var url = Convert.ToString(weburl);
var uname = Convert.ToString(username);
var pass = Convert.ToString(password);
var connLimit = Convert.ToString(connectionLimit);
int conLimit = Convert.ToInt32(connLimit);
try
{
if (!(string.IsNullOrEmpty(url) && string.IsNullOrEmpty(uname) && string.IsNullOrEmpty(pass) && conLimit > 0))
{
SqlContext.Pipe.Send("Entered inside the notify method");

HttpWebRequest httpWebRequest = WebRequest.Create(url) as HttpWebRequest;
string encoded = Convert.ToBase64String(Encoding.GetEncoding("ISO-8859-1").GetBytes(uname + ":" + pass));
httpWebRequest.Headers.Add("Authorization", "Basic " + encoded);
httpWebRequest.Method = "POST";
httpWebRequest.ContentLength = 0;
httpWebRequest.ServicePoint.ConnectionLimit = conLimit;

// Create an instance of the RequestState and assign the previous myHttpWebRequest
// object to its request field. 
RequestState requestState = new RequestState();
requestState.request = httpWebRequest;

SqlContext.Pipe.Send("before sending the notification");
//Start the asynchronous request.
IAsyncResult result =
(IAsyncResult)httpWebRequest.BeginGetResponse(new AsyncCallback(RespCallback), requestState);
SqlContext.Pipe.Send("after BeginGetResponse");

// this line implements the timeout, if there is a timeout, the callback fires and the request becomes aborted
ThreadPool.RegisterWaitForSingleObject(result.AsyncWaitHandle, new WaitOrTimerCallback(TimeoutCallback), requestState, DefaultTimeout, true);
//SqlContext.Pipe.Send("after RegisterWaitForSingleObject");

// The response came in the allowed time. The work processing will happen in the 
// callback function.
allDone.WaitOne();
//SqlContext.Pipe.Send("after allDone.WaitOne();");

// Release the HttpWebResponse resource.
requestState.response.Close();
SqlContext.Pipe.Send("after requestState.response.Close()");
}
}
catch (Exception exception)
{
SqlContext.Pipe.Send(" Main Exception");
SqlContext.Pipe.Send(exception.Message.ToString());
//TODO: log the details in a error table
SendNotifyErrorEmail(exception, null);
}
}
}
#endregion

#region ResposnseCallBack
/// <summary>
/// asynchronous Httpresponse callback
/// </summary>
/// <param name="asynchronousResult"></param>
private static void RespCallback(IAsyncResult asynchronousResult)
{
try
{
SqlContext.Pipe.Send("Entering the respcallback");
// State of request is asynchronous.
RequestState httpRequestState = (RequestState)asynchronousResult.AsyncState;
HttpWebRequest currentHttpWebRequest = httpRequestState.request;
httpRequestState.response = (HttpWebResponse)currentHttpWebRequest.EndGetResponse(asynchronousResult);
SqlContext.Pipe.Send("exiting the respcallBack");
}
catch (Exception ex)
{
SqlContext.Pipe.Send("exception in the respcallBack");
SendNotifyErrorEmail(ex, null);
}
allDone.Set();
}
#endregion
}
公共类请求状态
{
//此类存储请求的状态。
//const int BUFFER_SIZE=1024;
//公共数据;
//公共字节[]缓冲读取;
公共HttpWebRequest请求;
公共HttpWebResponse;
//公共河流响应;
公共请求状态()
{
//BufferRead=新字节[缓冲区大小];
//requestData=new StringBuilder(“”);
请求=null;
//streamResponse=null;
}
}
公共部分类存储过程
{
私有静态SqlString _mailServer=null;
私有静态SqlString _port=null;
私有静态SqlString _fromAddress=null;
私有静态SqlString _toAddress=null;
私有静态SqlString_mailactusername=null;
私有静态SqlString _decryptedPassword=null;
私有静态SqlString _subject=null;
私有静态字符串_mailContent=null;
私有静态int_portNo=0;
public static ManualResetEvent allDone=新的ManualResetEvent(false);
const int DefaultTimeout=20000;//50秒超时
#区域超时回调
/// 
///如果计时器触发,则中止请求。
/// 
///请求状态
///超时状态
私有静态void TimeoutCallback(对象状态,bool timedOut)
{
if(timedOut)
{
HttpWebRequest请求=状态为HttpWebRequest;
if(请求!=null)
{
request.Abort();
SendNotifyErrorEmail(null,“请求得到了timedOut!,请检查API”);
}
}
}
#端区
#区域API通知
[SqlProcedure]
public static void Notify(SqlString weburl、SqlString用户名、SqlString密码、SqlString connectionLimit、SqlString mailServer、SqlString端口、SqlString fromAddress
,SqlString地址,SqlString mailAcctUserName,SqlString mailAcctPassword,SqlString主题)
{
_mailServer=mailServer;
_端口=端口;
_fromAddress=fromAddress;
_地址=地址;
_MailAccutUserName=MailAccutUserName;
_decryptedPassword=mailAcctPassword;
_主题=主题;
if(!(weburl.IsNull&&username.IsNull&&password.IsNull&&connectionLimit.IsNull))
{
var url=Convert.ToString(weburl);
var uname=Convert.ToString(用户名);
var pass=Convert.ToString(密码);
var connLimit=Convert.ToString(connectionLimit);
int conLimit=转换为INT32(connLimit);
尝试
{
if(!(string.IsNullOrEmpty(url)和&string.IsNullOrEmpty(uname)和&string.IsNullOrEmpty(pass)和&conLimit>0))
{
SqlContext.Pipe.Send(“在notify方法中输入”);
HttpWebRequest HttpWebRequest=WebRequest.Create(url)为HttpWebRequest;
string encoded=Convert.ToBase64String(Encoding.GetEncoding(“ISO-8859-1”).GetBytes(uname+”:“+pass));
httpWebRequest.Headers.Add(“授权”、“基本”+编码);
httpWebRequest.Method=“POST”;
httpWebRequest.ContentLength=0;
httpWebRequest.ServicePoint.ConnectionLimit=conLimit;
//创建RequestState的实例并分配上一个myHttpWebRequest
//对象的请求字段。
RequestState RequestState=新的RequestState();
requestState.request=httpWebRequest;
SqlContext.Pipe.Send(“在发送通知之前”);
//启动异步请求。
IAsyncResult结果=
(IAsyncResult)httpWebRequest.BeginGetResponse(新的AsyncCallback(RespCallback),requestState);
SqlContext.Pipe.Send(“在BeginGetResponse之后”);
//这一行实现超时,如果有超时,将触发回调并中止请求
RegisterWaitForSingleObject(result.AsyncWaitHandle,new WaitOrTimerCallback(TimeoutCallback),requestState,DefaultTimeout,true);
//SqlContext.Pipe.Send(“在RegisterWaitForSingleObject之后”);
//响应在允许的时间内到达。工作处理将在
//回调函数。
全部完成。WaitOne();
//SqlContext.Pipe.Send(“after allDone.WaitOne();”;
//释放HttpWebResponse资源。
requestState.response.Close();
SqlContext.Pipe.Send(“在requestState.response.Close()之后”);
}
}
捕获(异常)
{
SqlContext.Pipe.Send(“主异常”);
SqlContext.Pipe.Send(exception.Message.ToString());
//TODO:将详细信息记录在错误表中
SendNotifyErrorEmail(异常,空);
}
}
}
#端区
#区域响应回调
///