HttpWebRequest runs slowly first time within SQLCLR - sql-server-2005

When making an HttpWebRequest within a CLR stored procedure (as per the code below), the first invocation after the Sql Server is (re-)started or after a given (but indeterminate) period of time waits for quite a length of time on the GetResponse() method call.
Is there any way to resolve this that doesn't involve a "hack" such as having a Sql Server Agent job running every few minutes to try and ensure that the first "slow" call is made by the Agent and not "real" production code?
function SqlString MakeWebRequest(string address, string parameters, int connectTO)
{
SqlString returnData;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(String.Concat(address.ToString(), "?", parameters.ToString()));
request.Timeout = (int)connectTO;
request.Method = "GET";
using (WebResponse response = request.GetResponse())
{
using (Stream responseStream = response.GetResponseStream())
{
using (StreamReader reader = new StreamReader(responseStream))
{
SqlString responseFromServer = reader.ReadToEnd();
returnData = responseFromServer;
}
}
}
response.Close();
return returnData;
}
(Error handling and other non-critical code has ben removed for brevity)
See also this Sql Server forums thread.

This was a problem for me using HttpWebRequest at first. It's due to the the class looking for a proxy to use. If you set the object's Proxy value to null/Nothing, it'll zip right along.

Looks to me like code signing verification. The MS shipped system dlls are all signed and SQL verifies the signatures at load time. Apparently the certificate revocation list is expired and the certificate verification engine times out retrieving a new list. I have blogged about this problem before Fix slow application startup due to code sign validation and the problem is also described in this Technet article: Certificate Revocation and Status Checking.
The solution is pretty arcane and involves registry editing of the key: HKLM\SOFTWARE\Microsoft\Cryptography\OID\EncodingType 0\CertDllCreateCertificateChainEngine\Config:
ChainUrlRetrievalTimeoutMilliseconds This is each individual CRL check call timeout. If is 0 or not present the default value of 15 seconds is used. Change this timeout to a reasonable value like 200 milliseconds.
ChainRevAccumulativeUrlRetrievalTimeoutMilliseconds This is the aggregate CRL retrieval timeout. If set to 0 or not present the default value of 20 seconds is used. Change this timeout to a value like 500 milliseconds.
There is also a more specific solution for Microsoft signed assemblies (this is from the Biztalk documentation, but applies to any assembly load):
Manually load Microsoft Certificate
Revocation lists
When starting a .NET application, the
.NET Framework will attempt to
download the Certificate Revocation
list (CRL) for any signed assembly. If
your system does not have direct
access to the Internet, or is
restricted from accessing the
Microsoft.com domain, this may delay
startup of BizTalk Server. To avoid
this delay at application startup, you
can use the following steps to
manually download and install the code
signing Certificate Revocation Lists
on your system.
Download the latest CRL updates from
http://crl.microsoft.com/pki/crl/products/CodeSignPCA.crl
and
http://crl.microsoft.com/pki/crl/products/CodeSignPCA2.crl.
Move the CodeSignPCA.crl and CodeSignPCA2.crl files to the isolated
system.
From a command prompt, enter the following command to use the certutil
utility to update the local
certificate store with the CRL
downloaded in step 1:
certutil –addstore CA c:\CodeSignPCA.crl
The CRL files are updated regularly,
so you should consider setting a
reoccurring task of downloading and
installing the CRL updates. To view
the next update time, double-click the
.crl file and view the value of the
Next Update field.

Not sure but if the delay long enough that initial DNS lookups could be the culprit?
( how long is the delay verse a normal call? )
and/or
Is this URI internal to the Network / or a different internal network?
I have seen some weird networking delays from using load balance profiles inside a network that isn't setup right, the firewalls, load-balancers, and other network profiles might be "fighting" the initial connections...
I am not a great networking guy, but you might want to see what an SA has to say about this on serverfault.com as well...
good luck

There is always a delay the first time SQLCLR loads the necessary assemblies.
That should be the case not only for your function MakeWebRequest, but also for any .NET function in the SQLCLR.

HttpWebRequest is part of the System.Net assembly, which is not part of the supported libraries.
I'd recommend using the library System.Web.Services instead to make web service calls from inside the SQLCLR.

I have tested and my first cold run (after SQL service restart) was in 3 seconds (not 30 as yours), all others are in 0 sec.
The code sample I've used to build a DLL:
using System;
using System.Data;
using System.Net;
using System.IO;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
namespace MySQLCLR
{
public static class WebRequests
{
public static void MakeWebRequest(string address, string parameters, int connectTO)
{
string returnData;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(String.Concat(address.ToString(), "?", parameters.ToString()));
request.Timeout = (int)connectTO;
request.Method = "GET";
using (WebResponse response = request.GetResponse())
{
using (Stream responseStream = response.GetResponseStream())
{
using (StreamReader reader = new StreamReader(responseStream))
{
returnData = reader.ReadToEnd();
reader.Close();
}
responseStream.Close();
}
response.Close();
}
SqlDataRecord rec = new SqlDataRecord(new SqlMetaData[] { new SqlMetaData("response", SqlDbType.NVarChar, 10000000) });
rec.SetValue(0, returnData);
SqlContext.Pipe.Send(rec);
}
}
}

Related

How to implement TLS 1.2 in an Android Xamarin C# receive an email, outlook.office365 using POP

Until late last week, emails sent to the android phone were being receiving and displayed fine. I've been told that 'it looks as though Microsoft have now fully discontinued the use of the smtp authentication, without TLS 1.2.'
How can I implement TLS 1.2 in the code? Code is below - it worked fine till last Friday. The app fails at the line ' client.Authenticate' with the error message 'Authentication failed'. The username and password are correct (but changed here for obvious reasons).
public void CheckForEmailsFromSupportPOP2(object sender, EventArgs e)
{
int numCountEmailsDownloaded = 0;
string strAllIncidentNumbers = "";
try
{
//int numCount = 1;
string pathLog = System.Environment.GetFolderPath(System.Environment.SpecialFolder.LocalApplicationData);
string fileNameLog = Path.Combine(pathLog, "pop3.txt");
using (var client = new Pop3Client(new ProtocolLogger(fileNameLog)))
{
client.Connect("outlook.office365.com", 995, SecureSocketOptions.SslOnConnect);
client.Authenticate("mobile1#zxcv.co.uk", "password"); //<<<<<<<<<FAILS HERE
for (int i = 0; i < client.Count; i++)
{
var message = client.GetMessage(i);
... and so on.
Thank you for your help.
If you have clients that can’t use TLS1.2, you may use the opt-in legacy endpoint by now. However, in 2022, Microsoft official team plan to disable those older TLS versions to secure their customers and meet compliance requirements. Due to significant usage, Microsoft official team has created an opt-in endpoint that legacy clients can use with TLS1.0 and TLS1.1. However, only WW customers will be able to use this new endpoint. To take advantage of this new endpoint, you will have to:
Set the AllowLegacyTLSClients parameter on the Set-TransportConfig cmdlet to True.
Legacy clients and devices will need to be configured to submit using the new endpoint smtp-legacy.office365.com.
If you want to use TLS1.2 early, you can set the AllowLegacyTLSClients parameter to False. In fact, since September 2021, Microsoft has rejected a small percentage of connections that use TLS1.0 for SMTP AUTH. For more details about this, you may refer to these links: "https://techcommunity.microsoft.com/t5/exchange-team-blog/new-opt-in-endpoint-available-for-smtp-auth-clients-still/ba-p/2659652" and "https://learn.microsoft.com/en-us/exchange/clients-and-mobile-in-exchange-online/opt-in-exchange-online-endpoint-for-legacy-tls-using-smtp-auth".

vb Could not establish secure channel for SSL/TLS

I am working on a project which I did not write, have inherited, and have an issue that I'm not sure quite how to solve. My background is not in .NET, so please excuse anything that doesn't sound right, as I may not know what the correct terminology should be.
We are using Visual Studio 2008 to compile a project that is running on Windows CE 6.0. We are using the Compact Framework v2.0. The software is running on an Embedded processor in a network (WIFI) connected industrial environment. The main UI is written in VB, and all of the supporting DLLs are written using C#.
Up until now we've only been required to connect to http (non-secure) web addresses for GET requests. We now have a requirement to switch these addresses over to https (secure) for security's sake.
The HttpWebRequest is built/submitted from VB. When I provide the code with the https address, I get the "Could not establish secure channel for SSL/TLS" error that is in the subject.
Here is the code for that request:
Dim myuri As System.Uri = New System.Uri(sUrl)
Dim myHttpwebresponse As HttpWebResponse = Nothing
Dim myhttpwebrequest As HttpWebRequest = CType(WebRequest.Create(myuri), HttpWebRequest)
myhttpwebrequest.KeepAlive = False
myhttpwebrequest.Proxy.Credentials = CredentialCache.DefaultCredentials
myhttpwebrequest.ContentType = "text/xml"
myhttpwebrequest.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
myhttpwebrequest.AllowAutoRedirect = False
myhttpwebrequest.Timeout = 150000
Dim mycred As NetworkCredential = New NetworkCredential(username, password)
Dim myCredentialCache As CredentialCache = New CredentialCache()
myCredentialCache.Add(myuri, "Basic", mycred)
myhttpwebrequest.Credentials = myCredentialCache
myhttpwebrequest.Method = "GET"
myhttpwebrequest.ProtocolVersion = HttpVersion.Version10
ServicePointManager.CertificatePolicy = New AcceptServerNameMismatch
myHttpwebresponse = CType(myhttpwebrequest.GetResponse(), HttpWebResponse)
I have done quite a bit of reading over the last day or so that indicate that the CertificatePolicy is where I can override the ICertificatePolicy classes to essentially validate all SSL requests. Definitely not safe, and not ideal, but I'm not sure of another way to handle these requests.
My class to do this is:
Public Class MyCertificatePolicy
Implements ICertificatePolicy
Public Shared DefaultValidate As Boolean = True
Public Sub trustedCertificatePolicy()
End Sub
Public Function CheckValidationResult(ByVal srvPoint As ServicePoint, _
ByVal cert As X509Certificate, ByVal request As WebRequest, ByVal problem As Integer) _
As Boolean Implements ICertificatePolicy.CheckValidationResult
Return True
End Function
End Class
Unfortunately when the response comes back, it never calls CheckValidationResult(). Thus, no validation and the error.
So my questions...
The "Right" way to do this according to everything that I've read is to use the ServerCertificateValidationCallback. Unfortunately with the version of Compact Framework that we are using (maybe all?) it is not included. Is there something that I'm missing that would cause that function not to get called?
Again, from what I've read, I believe that the Framework that we're running on doesn't support TLS v1.1 or v1.2. Which most current servers are running. Is there a way in VB to get around this?
Is there another Request method that can be used?
Any help or guidance as to where to go from here is greatly appreciated!
You need to install the trusted root certificate on the device(s), that matches the SSL certificate on your server.
Or change the certificate on the server to match one of the Trusted Roots on the device(s). By default, the devices ship with a very small number of trusted CAs, unlike desktop browsers that contain nearly every CA in the world.

.Net Core ReportExecutionServiceSoapClient set credentials

I am using ReportExecutionServiceSoapClient in .Net Core i got the latest version of .net Core and tried to get a report from reporting services to work. after I've used the WCF connection service I was able to add the code with looks like bellow
// Instantiate the Soap client
ReportExecutionServiceSoap rsExec = new ReportExecutionServiceSoapClient(ReportExecutionServiceSoapClient.EndpointConfiguration.ReportExecutionServiceSoap);
// Create a network credential object with the appropriate username and password used
// to access the SSRS web service
string historyID = null;
TrustedUserHeader trustedUserHeader = new TrustedUserHeader();
ExecutionHeader execHeader = new ExecutionHeader();
// Here we call the async LoadReport() method using the "await" keyword, which means any code below this method
// will not execute until the result from the LoadReportAsync task is returned
var taskLoadReport = rsExec.LoadReportAsync(reportPath, historyID);
// By the time the LoadReportAsync task is returned successfully, its "executionInfo" property
// would have already been populated. Now the remaining code in this main thread will resume executing
string deviceInfo = null;
string format = "EXCEL";
// Now, similar to the above task, we will call the RenderAsync() method and await its result
var taskRender = await rsExec.RenderAsync(renderReq);
When it hist renderAsync all falls apart because the credentials for the service are not set anywhere. I've tried to Login async with no success. Also I've tried to set the credentials with SetExecutionCredentialsAsync but I've got and error saying "The HTTP request is unauthorized with client authentication scheme 'Anonymous'. The authentication header received from the server was 'NTLM'." I don't know how to change that for ReportExecutionServiceSoapClient.
I have read some posts in which Microsoft guys says that the authentication with a soap is not resolved but for me it seems so close to be true. I feel like I am missing something.
Technology stack: VS 2017, .net Core web api, ssrs 2016, sql server 2016 standard
How can I authenticate the user for this call?
I know this is an old question but I had the same issue and stumbled onto the answer.
After creating the ReportExecutionServiceSoap object you can specify the username and password in the ClientCredentials. I've had success with this using the Basic client credential type. Be sure you are using HTTPS, otherwise your password is sent in plaintext to the reporting server. I also recommend storing the user/password in a secure place and not code.
BasicHttpBinding rsBinding = new BasicHttpBinding();
rsBinding.Security.Mode = BasicHttpSecurityMode.TransportCredentialOnly;
rsBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
EndpointAddress rsEndpointAddress = new EndpointAddress("https://servername/ReportServer/ReportExecution2005.asmx");
var rsExec = new ReportExecutionServiceSoapClient(rsBinding, rsEndpointAddress);
rsExec.ClientCredentials.UserName.UserName = "username";
rsExec.ClientCredentials.UserName.Password = "pass";

FtpWebResponse GetResponse() gives "The remote server returned an error: (550) File unavailable (e.g., file not found, no access)."

I have a Win Form with a picture gallery that uses FtpWebRequest to upload pictures, but after changing to .Net 4.0 I suddenly get 550 error. The error occurs both when uploading files and listing directory.
As seen in my example-code I have implemented the MS solution from http://support.microsoft.com/kb/2134299.
I have checked the username, password and path - everything is correct.
Still, I get an error. I have skimmed Google for every solution without any response.
SetMethodRequiredCWD();
FtpWebRequest reqFTP = (FtpWebRequest)WebRequest.Create(new Uri(pPath));
reqFTP.Credentials = new NetworkCredential(Properties.Settings.Default.FTPUser, Properties.Settings.Default.FTPPass);
reqFTP.Method = WebRequestMethods.Ftp.ListDirectory;
reqFTP.KeepAlive = false;
FtpWebResponse respFTP = (FtpWebResponse)reqFTP.GetResponse();
Stream respStreamFTP = respFTP.GetResponseStream();
StreamReader streamReader = new StreamReader(respStreamFTP, Encoding.Default);
One approach I would recommend is to monitor the request/response exchange between the ftp-client and -server using e.g. Fiddler.
First, record a session in which the error does not manifest by manually using a third party client such as Filezilla to upload the file. Then, record another session with your program as the client. Comparing the exchanged messages may yield some insight to what is wrong.
Try to enable Network Tracing: http://msdn.microsoft.com/en-us/library/a6sbz1dx%28v=vs.100%29.aspx

Upload large file to Sharepoint with Silverlight

I am trying to upload a photo to a sharepoint library. If I use a relatively small file (370KB) then it works without any problems.
But if I try to upload a file that is about 3MB large then I get the error:
"Der Remoteserver hat einen Fehler zurückgegeben: NotFound."
translated:
"The remote server returned an error: NotFound."
I read that it should be possible to set the max message size, but I found no way to set such a thing in the ClientContext object.
This is the code I use:
private void UploadFileCallback(object state)
{
var args = (List<object>)state;
var itemContainer = (ISharepointItemContainer)args.ElementAt(0);
var fileInfo = (FileInfo)args.ElementAt(1);
var sharepointList = _context.Web.Lists.GetByTitle(itemContainer.ListName);
Microsoft.SharePoint.Client.File uploadFile;
FileCreationInformation newFile;
using (FileStream fs = fileInfo.OpenRead())
{
byte[] content = new byte[fs.Length];
newFile = new FileCreationInformation();
int dummy = fs.Read(content, 0, (int)fs.Length);
newFile.Content = content;
newFile.Url = itemContainer.AbsoluteUrl + "/" + fileInfo.Name;
uploadFile = sharepointList.RootFolder.Files.Add(newFile);
_context.Load(uploadFile);
}
_context.ExecuteQuery();
if (FileUploadCompleted != null)
{
FileUploadCompleted(this, EventArgs.Empty);
}
}
Does anyone have an idea on how to resolve this issue?
The first thing to try is to go to the Web Applications Management section in the Central Administration site for SharePoint. Select the General Settings for the web app that you are deploying to and increase the maximum upload size.
The second thing to try is to add this to your web.config:
<system.webServer>
<security>
<requestFiltering>
<requestLimits maxAllowedContentLength="52428800"/>
</requestFiltering>
</security>
</system.webServer>
This will let you set the size to something larger.
By default, SharePoint has a 50MB max limit per upload. IIS 7 (not sure about other versions) has a 30 MB max limit per upload. You will need to add the XML configuration that Ryan provided to your SharePoint website's web.config, in IIS. This is your front-end web server.
The limit you're reaching is because the webservice that handles Client Object Model requests has a maximum message size. You can either increase that size, but another solution is to use WebDAV to upload the document, this will help if you don't have access to the server.
The .NET Client Object Model has a method File.SaveBinraryDirect() for that, and that's probably your best bet.
If you were using the Silverlight Client Object Model that method is not available and you'll have write some additional code: see this article, second part. The first part descibes how to increase the maximum message size.
This should increase your maximum upload size to the one set in Central Admin (typically 50MB), pointed out in other posts.
The default upload size limit for the SharePoint client object model is 2 MB. You can change that limit by modifying the MaxReceivedMessageSize property of the service.
This can be done in two ways:
programatically - as described in this link - tho this won't work in Silverlight for example
trough the powershell. On the server where you have SharePoint installed, fire up the SharePoint Management Shell (make sure you run it under the farm administrator account) and run the following commands.
$ws = [Microsoft.SharePoint.Administration.SPWebService]::ContentService
$ws.ClientRequestServiceSettings.MaxReceivedMessageSize = 52428800
$ws.Update()
This will change the upload limit to 52428800 bytes - or 50 MB. Now, restart the website hosting your SharePoint site (or the entire IIS) for the changes to take effect.