none
ASP.Net C# Response.Redirect() method all the way cannot work somehow RRS feed

  • Question

  • I have a C# ASP.Net program, which needs to redirect to another URL when receiving a form request in the postback web page. However, all the way the Response.Redirect() (in line 91 of the program RedirectTest.aspx.cs) method cannot work: it always stays at the current web page. I have almost used up all resorts to make the Response.Redirect() work, including applying both true and false values in the "endResponse" argument of the Response.Redirect() method, using the HttpContext.Current.ApplicationInstance.CompleteRequest() method, and also trying to redirect to some popular URLs, like google, yahoo, ... But all the tries failed somehow.

    The full set of the source codes of my C# ASP.Net program RedirectTest.aspx.cs is shown below. Thanks for any help!

    +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Security.Cryptography;
    using System.Security.Cryptography.Xml;
    using System.Xml;
    using System.IO;
    using System.Text;
    using System.Configuration;
    using System.ComponentModel;
    using System.Net;
    using System.Threading;

    namespace RedirectClient
    {
    public partial class RedirectClient : System.Web.UI.Page
    {
    public static string sessionID;
    public static string respXML;
    public static byte[] Key;
    public static byte[] IV;
    public static string UserId;
    public static string LoginResult;
    public static string strMPassResultDesc;
    public static HttpCookie myCookie;
    protected void Page_Load(object sender, EventArgs e)
    {

    InitializeKeyIV();

    if (Request.Form["ResponseEnvelope"] != null)
    {
    string myURL = HttpContext.Current.Request.Url.AbsoluteUri;
    string strReqEnvelope = Request.Form["ResponseEnvelope"].ToString();
    log_msg(ConfigurationManager.AppSettings["LogFile"], string.Format("Page_Load(): received Request.Form, strReqEnvelope = ({0}).", strReqEnvelope));
    fnResponse(strReqEnvelope);
    }
    else
    {
    sessionID = Request.QueryString["sessionID"];
    if((sessionID==null)||(sessionID == string.Empty))
    sessionID = GetRandomString(9);
    CreateRequest();
    }
    }

    public void fnResponse(string respXML)
    {
    try
    {
    string Test_Internal_Key = ConfigurationManager.AppSettings["Test_Internal_Key"];
    string redirectURL;
    string LoginResult = string.Empty;
    if (respXML != string.Empty)
    {
    if (VerifyResponseEnvelope(respXML, ref LoginResult))
    {
    // Get Response Result
    string strMPassRet = respXML.Substring(respXML.IndexOf("<RETEST_RESULT>") + 14, respXML.IndexOf("</RETEST_RESULT>") - respXML.IndexOf("<RETEST_RESULT>") - 14);
    string[] strResult = strMPassRet.Split('|');
    if (strResult.Length != 3)
    {
    log_msg(ConfigurationManager.AppSettings["LogFile"], "Unable to get UserID from Response Envelope.");
    }
    else
    {
    UserId = strResult[0];
    string sign = strResult[2];
    log_msg(ConfigurationManager.AppSettings["LogFile"], string.Format("User ID: {0}\r\nLogin Result: {1}", UserId, LoginResult));
    }
    strMPassResultDesc = respXML.Substring(respXML.IndexOf("<RETEST_RESULT_DESC>") + 19, respXML.IndexOf("</RETEST_RESULT_DESC>") - respXML.IndexOf("<RETEST_RESULT_DESC>") - 19);
    string clientUniqueID = respXML.Substring(respXML.IndexOf("<RETEST_UNIQUE_ID>") + 17, respXML.IndexOf("</RETEST_UNIQUE_ID>") - respXML.IndexOf("<RETEST_UNIQUE_ID>") - 17);
    sessionID = clientUniqueID.Substring(0, 9);

    redirectURL = ConfigurationManager.AppSettings["TBSServerURL"] + "?userid=" + Encrypt(UserId) + "&skey=" + Encrypt(Test_Internal_Key) + "&sessionID=" + sessionID;
    }
    else
    {
    redirectURL = string.Format("~/FailPage.aspx?code={0}&sessionID={1}", LoginResult, sessionID);
    }
    string RedirectURLFile = Path.Combine(ConfigurationManager.AppSettings["RedirectURLFolder"], sessionID + @".txt");
    File.WriteAllText(RedirectURLFile, redirectURL);
    log_msg(ConfigurationManager.AppSettings["LogFile"], string.Format("fnResponse(): redirectURL = ({0}).", redirectURL));
    // Response.Redirect(redirectURL, false);
    // HttpContext.Current.ApplicationInstance.CompleteRequest();
    try
    {
    Response.Redirect(redirectURL, true); // this Response.Redirect() method in a postback web page cannot work at all
    }
    catch (ThreadAbortException ex)
    {
    // eat it
    }
    }
    else
    log_msg(ConfigurationManager.AppSettings["LogFile"], "There is no response message.");
    }
    catch (Exception ex)
    {
    log_msg(ConfigurationManager.AppSettings["LogFile"], string.Format("Response: {0}", ex.ToString()));
    }
    }

    private bool VerifyResponseEnvelope(string strEnvelope, ref string retCode)
    {
    try
    {
    RSAParameters param1;
    ASCIIEncoding ascEnc = new ASCIIEncoding();
    clsRSA clsRSA = new clsRSA();
    clsStringHelper clsSH = new clsStringHelper();
    byte[] btSignData;
    byte[] btSignature;
    string path = ConfigurationManager.AppSettings["PublicKeyFile"];
    clsRSA.initCrypto(path);
    param1 = clsRSA.exportParameters(false);
    if (strEnvelope != "")
    {
    log_msg(ConfigurationManager.AppSettings["LogFile"], string.Format("Response Data: {0}", strEnvelope));
    btSignData = ascEnc.GetBytes(strEnvelope.Substring(0, strEnvelope.IndexOf("<RETESTResponseFooter>")));
    btSignature = clsSH.HexStringToBytes(strEnvelope.Substring(strEnvelope.IndexOf("<RETEST_DS>") + 10, strEnvelope.IndexOf("</RETEST_DS>") - strEnvelope.IndexOf("<RETEST_DS>") - 10));
    if (clsRSA.VerifyHash(btSignData, btSignature))
    {
    retCode = strEnvelope.Substring(strEnvelope.IndexOf("<RETEST_ID>") + 10, strEnvelope.IndexOf("</RETEST_ID>") - strEnvelope.IndexOf("<RETEST_ID>") - 10);
    log_msg(ConfigurationManager.AppSettings["LogFile"], string.Format("Response Code : {0}", retCode));
    if (retCode == "0000")
    return (true);
    else
    return (false);
    }
    else
    {
    retCode = "0006";
    log_msg(ConfigurationManager.AppSettings["LogFile"], "Response Packet Signature is Invalid.");
    return (false);
    }
    }
    }
    catch (Exception ex)
    {
    log_msg(ConfigurationManager.AppSettings["LogFile"], string.Format("Envelope: {0} {1}", strEnvelope, ex.ToString()));
    }
    return (false);
    }

    // Daniel, 24May19, for debugging purpose
    public static void log_msg(string filename, string msg)
    {
    string myPath = String.Empty;
    if (!string.IsNullOrEmpty(filename))
    {
    myPath = Path.GetDirectoryName(filename);
    if (!Directory.Exists(myPath))
    Directory.CreateDirectory(myPath);

    if (File.Exists(filename))
    {
    // Append to existing file.
    using (StreamWriter sw = File.AppendText(filename))
    {
    sw.WriteLine("\r\n" + DateTime.Now.ToString("yyyyMMdd HH:mm:ss.fff") + " - " + msg);
    }
    }
    else
    {
    // Create a file to write to.
    using (StreamWriter sw = File.CreateText(filename))
    {
    sw.WriteLine(DateTime.Now.ToString("yyyyMMdd HH:mm:ss.fff") + " - " + msg);
    }
    }
    }
    }

    private string ByteArrayToHexString(byte[] Bytes)
    {
    StringBuilder Result = new StringBuilder(Bytes.Length * 2);
    string HexAlphabet = "0123456789ABCDEF";

    foreach (byte B in Bytes)
    {
    Result.Append(HexAlphabet[(int)(B >> 4)]);
    Result.Append(HexAlphabet[(int)(B & 0xF)]);
    }
    return Result.ToString();
    }

    private byte[] HexStringToByteArray(string Hex)
    {
    byte[] Bytes = new byte[Hex.Length / 2];
    int[] HexValue = new int[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
    0x06, 0x07, 0x08, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F };

    for (int x = 0, i = 0; i < Hex.Length; i += 2, x += 1)
    {
    Bytes[x] = (byte)(HexValue[Char.ToUpper(Hex[i + 0]) - '0'] << 4 |
    HexValue[Char.ToUpper(Hex[i + 1]) - '0']);
    }
    return Bytes;
    }

    private void InitializeKeyIV()
    {
    Key = CreateKey(ConfigurationManager.AppSettings["PassWord"]);
    IV = CreateIV(ConfigurationManager.AppSettings["PassWord"]);
    }

    private byte[] CreateKey(string strPassword)
    {
    // Convert strPassword to an array and store in chrData.
    char[] chrData = strPassword.ToCharArray();
    // Use intLength to get strPassword size.
    int intLength = chrData.Length;
    // Declare bytDataToHash and make it the same size as chrData.
    byte[] bytDataToHash = new byte[intLength];
    bytDataToHash = Encoding.ASCII.GetBytes(chrData);

    // Declare what hash to use.
    SHA512Managed SHA512 = new SHA512Managed();
    // Declare bytResult, Hash bytDataToHash and store it in bytResult.
    byte[] bytResult = SHA512.ComputeHash(bytDataToHash);
    // Declare bytKey(31). It will hold 256 bits.
    byte[] bytKey = new byte[32];

    // Use For Next to put a specific size (256 bits) of
    // bytResult into bytKey. The 0 To 31 will put the first 256 bits
    // of 512 bits into bytKey.
    for (int i = 0; i < 32; i++)
    bytKey[i] = bytResult[i];

    return (bytKey);
    }

    private byte[] CreateIV(string strPassword)
    {
    // Convert strPassword to an array and store in chrData.
    char[] chrData = strPassword.ToCharArray();
    // Use intLength to get strPassword size.
    int intLength = chrData.Length;
    // Declare bytDataToHash and make it the same size as chrData.
    byte[] bytDataToHash = new byte[intLength];
    bytDataToHash = Encoding.ASCII.GetBytes(chrData);

    // Declare what hash to use.
    SHA512Managed SHA512 = new SHA512Managed();
    // Declare bytResult, Hash bytDataToHash and store it in bytResult.
    byte[] bytResult = SHA512.ComputeHash(bytDataToHash);
    // Declare bytKey, It will hold 128 bits.
    byte[] bytIV = new byte[16];

    // Use For Next to put a specific size (128 bits) of
    // bytResult into bytIV. The 0 To 30 for bytKey used the first 256 bits.
    // of the hashed password. The 32 To 47 will put the next 128 bits into bytIV.
    for (int i = 32; i <= 47; i++)
    bytIV[i - 32] = bytResult[i];

    return (bytIV);
    }


    public byte[] GetBytes(string inputStr)
    {
    byte[] bytes = Encoding.UTF8.GetBytes(inputStr);
    return (bytes);
    }

    protected string GetRandomString(int returnStringLength,
    string chooseFromString = "0123456789")
    {
    Random random = new Random();
    return new string(Enumerable.Repeat(chooseFromString, returnStringLength)
    .Select(s => s[random.Next(s.Length)]).ToArray());
    }

    protected string applyDigitalSignature(string data)
    {
    String xmlText = File.ReadAllText(ConfigurationManager.AppSettings["PrivateKeyFile"]);
    CspParameters cspParams = new CspParameters();
    cspParams.Flags = CspProviderFlags.UseDefaultKeyContainer;
    cspParams.KeyContainerName = ConfigurationManager.AppSettings["KeyContainerName"];
    RSACryptoServiceProvider csp = new RSACryptoServiceProvider(cspParams);
    csp.PersistKeyInCsp = true;
    csp.FromXmlString(xmlText);

    XmlDocument doc = new XmlDocument();
    doc.PreserveWhitespace = true;
    doc.LoadXml(data);
    // Sign the XML document.
    SignXml(doc, csp);
    return (XmlDoc2String(doc));
    }

    // Sign an XML file.
    // This document cannot be verified unless the verifying
    // code has the key with which it was signed.
    public static void SignXml(XmlDocument xmlDoc, RSA rsaKey)
    {
    // Check arguments.
    if (xmlDoc == null)
    throw new ArgumentException(nameof(xmlDoc));
    if (rsaKey == null)
    throw new ArgumentException(nameof(rsaKey));

    // Create a SignedXml object.
    SignedXml signedXml = new SignedXml(xmlDoc);

    // Add the key to the SignedXml document.
    signedXml.SigningKey = rsaKey;

    // Create a reference to be signed.
    Reference reference = new Reference();
    reference.Uri = "";

    // Add an enveloped transformation to the reference.
    XmlDsigEnvelopedSignatureTransform env = new XmlDsigEnvelopedSignatureTransform();
    reference.AddTransform(env);

    // Add the reference to the SignedXml object.
    signedXml.AddReference(reference);

    // Compute the signature.
    signedXml.ComputeSignature();

    // Get the XML representation of the signature and save
    // it to an XmlElement object.
    XmlElement xmlDigitalSignature = signedXml.GetXml();
    XmlNodeList elemList = xmlDoc.GetElementsByTagName("RETEST_DS");

    // Append the element to the XML document.
    elemList[0].AppendChild(xmlDoc.ImportNode(xmlDigitalSignature, true));
    }

    public static string XmlDoc2String(XmlDocument xmlDoc)
    {
    using (var sw = new StringWriter())
    using (var xw = XmlWriter.Create(sw))
    {
    xmlDoc.WriteTo(xw);
    xw.Flush();
    return sw.GetStringBuilder().ToString();
    }
    }

    protected void btnRedirect_Click(object sender, EventArgs e)
    {
    string userID = string.Empty;
    string code = retrieveReturnMPassValues(respXML, ref userID);
    if (code == "0000") // successful
    {
    string Test_Internal_Key = "12345";
    string succURL = ConfigurationManager.AppSettings["TestServerURL"] + "?userid=" + Encrypt(userID) + "&skey=" + Encrypt(Test_Internal_Key) + "&sessionID=" + sessionID;
    Response.Redirect(succURL);
    }
    else
    {
    string failURL = string.Format("~/FailPage.aspx?code={0}&sessionID={1}", code, sessionID);
    Response.Redirect(failURL);
    }
    }

    private string retrieveReturnMPassValues(string returnXML, ref string userID)
    {
    string returnCode = respXML.Substring(respXML.IndexOf("<RETEST_ID>") + 10, respXML.IndexOf("</RETEST_ID>") - respXML.IndexOf("<RETEST_ID>") - 10);
    string returnResult = respXML.Substring(respXML.IndexOf("<RETEST_RESULT>") + 14, respXML.IndexOf("</RETEST_RESULT>") - respXML.IndexOf("<RETEST_RESULT>") - 14);
    userID = returnResult.Split('|')[0].Trim();
    return (returnCode);
    }

    private string Encrypt(string clearText)
    {
    string EncryptionKey = "MYTEST32019";
    byte[] clearBytes = Encoding.Unicode.GetBytes(clearText);
    using (Aes encryptor = Aes.Create())
    {
    Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
    encryptor.Key = pdb.GetBytes(32);
    encryptor.IV = pdb.GetBytes(16);
    using (MemoryStream ms = new MemoryStream())
    {
    using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateEncryptor(), CryptoStreamMode.Write))
    {
    cs.Write(clearBytes, 0, clearBytes.Length);
    cs.Close();
    }
    clearText = Convert.ToBase64String(ms.ToArray());
    }
    }
    return clearText;
    }

    public static Boolean checkDigitalSignature(string xmlData)
    {
    // Create a new CspParameters object to specify
    // a key container.
    try
    {
    String xmlText = File.ReadAllText(ConfigurationManager.AppSettings["PublicKeyFile"]);
    CspParameters cspParams = new CspParameters();
    cspParams.Flags = CspProviderFlags.UseDefaultKeyContainer;
    cspParams.KeyContainerName = ConfigurationManager.AppSettings["KeyContainerName"];
    RSACryptoServiceProvider csp = new RSACryptoServiceProvider(cspParams);
    csp.PersistKeyInCsp = true;
    csp.FromXmlString(xmlText);

    // Create a new XML document.
    XmlDocument xmlDoc = new XmlDocument();

    // Load an XML file into the XmlDocument object.
    xmlDoc.PreserveWhitespace = true;
    xmlDoc.LoadXml(xmlData);

    // Verify the signature of the signed XML.
    Console.WriteLine("Verifying signature...");
    return (VerifyXml(xmlDoc, csp));
    }
    catch (Exception ex)
    {
    Console.WriteLine("checkDigitalSignature() error: " + ex.ToString());
    return (false);
    }
    }


    // Verify the signature of an XML file against an asymmetric
    // algorithm and return the result.
    public static Boolean VerifyXml(XmlDocument xmlDoc, RSA key)
    {
    // Check arguments.
    if (xmlDoc == null)
    throw new ArgumentException("xmlDoc");
    if (key == null)
    throw new ArgumentException("key");

    // Create a new SignedXml object and pass it
    // the XML document class.
    SignedXml signedXml = new SignedXml(xmlDoc);

    // Find the "Signature" node and create a new
    // XmlNodeList object.
    XmlNodeList nodeList = xmlDoc.GetElementsByTagName("Signature");

    // Throw an exception if no signature was found.
    if (nodeList.Count <= 0)
    {
    throw new CryptographicException("Verification failed: No Signature was found in the document.");
    }

    // This example only supports one signature for
    // the entire XML document. Throw an exception
    // if more than one signature was found.
    if (nodeList.Count >= 2)
    {
    throw new CryptographicException("Verification failed: More that one signature was found for the document.");
    }

    // Load the first <signature> node.
    signedXml.LoadXml((XmlElement)nodeList[0]);

    // Check the signature and return the result.
    return signedXml.CheckSignature(key);
    }

    protected void btnClear_Click(object sender, EventArgs e)
    {
    }

    public bool CreateRequest()
    {
    try
    {
    string urlS;

    StringBuilder strEnvelope = new StringBuilder();
    ASCIIEncoding ascEnc = new ASCIIEncoding();
    string strUniqueID;
    string strDigSign;
    byte[] btSign;

    // Daniel, 20190918, set the return URL by external ip address
    string sRetURL = ConfigurationManager.AppSettings["ReturnURL"] + @"?sessionid=" + sessionID;
    string sAgencyID = ConfigurationManager.AppSettings["RETEST_AGENCY_ID"];
    string sAppName = ConfigurationManager.AppSettings["RETEST_APP"];
    urlS = ConfigurationManager.AppSettings["MPassServerURL"];

    // Generate Random unique ID
    strUniqueID = sessionID + DateTime.Now.ToString("yyyyMMddhhmmss");
    // Create a digital envelope
    strEnvelope.Append("<RETESTRequestEnvelope>");
    strEnvelope.Append("<RETESTRequestHeader>");
    strEnvelope.Append("<RETEST_AGENCY_ID>" + sAgencyID + "</RETEST_AGENCY_ID>");
    strEnvelope.Append("<RETEST_APP>" + sAppName + "</RETEST_APP>");
    strEnvelope.Append("<RETEST_RET_URL>" + sRetURL + "</RETEST_RET_URL>");
    strEnvelope.Append("<RETEST_TIMESTAMP>" + DateTime.Now.ToString("yyyyMMddhhmmss") + "</RETEST_TIMESTAMP>");
    strEnvelope.Append("<RETEST_UNIQUE_ID>" + strUniqueID + "</RETEST_UNIQUE_ID>");
    strEnvelope.Append("</RETESTRequestHeader>");
    strEnvelope.Append("<RETESTRequestPayload>");
    strEnvelope.Append("<RETEST_SERVICE>Authentication</RETEST_SERVICE>");
    strEnvelope.Append("</RETESTRequestPayload>");

    // Create a digital signature
    btSign = ascEnc.GetBytes(strEnvelope.ToString());
    strDigSign = CreateSignature(btSign);
    strEnvelope.Append("<RETESTRequestFooter>");
    strEnvelope.Append("<RETEST_DS>" + strDigSign + "</RETEST_DS>");
    strEnvelope.Append("</RETESTRequestFooter>");
    strEnvelope.Append("</RETESTRequestEnvelope>");

    return (submit_form(strEnvelope.ToString(), urlS));
    }
    catch( Exception ex )
    {
    log_msg(ConfigurationManager.AppSettings["LogFile"], string.Format("Request: {0}", ex.ToString()));
    return (false);
    }
    }

    private bool submit_form(string strEnvelope, string destURL)
    {
    string postData = string.Empty;
    try
    {
    ASCIIEncoding encoding = new ASCIIEncoding();
    postData = "hdnEnvelope=" + strEnvelope;
    log_msg(ConfigurationManager.AppSettings["LogFile"], string.Format("submit_form(): postData = ({0}).", postData));
    byte[] data = encoding.GetBytes(postData);

    HttpWebRequest myRequest =
    (HttpWebRequest)WebRequest.Create(destURL);
    myRequest.Method = "POST";
    myRequest.ContentType = "application/x-www-form-urlencoded";
    myRequest.ContentLength = data.Length;
    log_msg(ConfigurationManager.AppSettings["LogFile"], string.Format("submit_form(): before sending to destURL ({0}).", destURL));
    Stream newStream = myRequest.GetRequestStream();
    newStream.Write(data, 0, data.Length);
    newStream.Close();
    log_msg(ConfigurationManager.AppSettings["LogFile"], string.Format("submit_form(): after sending to destURL ({0}).", destURL));
    return (true);
    }
    catch(Exception ex)
    {
    log_msg(ConfigurationManager.AppSettings["LogFile"], string.Format("submit_form(): {0}", ex.ToString()));
    return (false);
    }
    }

    private string CreateSignature(byte[] btData)
    {
    RSAParameters param;
    clsRSA rsa = new clsRSA();
    clsStringHelper clsSH = new clsStringHelper();
    clsRijnDael clsRD = new clsRijnDael();

    string sPrvKeyPwd = string.Empty;
    string strVendorPvtKey = string.Empty;
    try
    {
    using (StreamReader reader = new StreamReader(ConfigurationManager.AppSettings["PrivateKeyPasswordFile"]))
    {
    sPrvKeyPwd = reader.ReadLine();
    };
    string sPath = ConfigurationManager.AppSettings["PrivateKeyFile"];
    strVendorPvtKey = clsRD.DecryptFiletoData(sPath, sPrvKeyPwd);
    rsa.initCryptoUsingKey(strVendorPvtKey);
    param = rsa.exportParameters(true);
    return (clsSH.BytesToHexString(rsa.HashAndSign(btData)));
    }
    catch (Exception ex)
    {
    log_msg(ConfigurationManager.AppSettings["LogFile"], string.Format("Create Signature: {0}", ex.ToString()));
    throw ex;
    }
    finally
    {
    rsa = null;
    clsSH = null;
    clsRD = null;
    strVendorPvtKey = null;
    }
    }
    public int RandomGenerator()
    {
    byte[] byteCount = new byte[6];
    RNGCryptoServiceProvider randomNumber = new RNGCryptoServiceProvider();

    randomNumber.GetBytes(byteCount);
    return (BitConverter.ToInt32(byteCount, 0));
    }

    protected void btnRequest_Click(object sender, EventArgs e)
    {
    CreateRequest();
    }

    protected void Timer1_Tick(object sender, EventArgs e)
    {
    string RedirectUrlFile = Path.Combine(ConfigurationManager.AppSettings["RedirectUrlFolder"], sessionID+@".txt");
    if (File.Exists(RedirectUrlFile))
    {
    string redirectURL = File.ReadAllText(RedirectUrlFile);
    File.Delete(RedirectUrlFile);
    Response.Redirect(redirectURL, false);
    }
    }
    }
    }

    +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++


    • Moved by CoolDadTx Friday, September 20, 2019 2:27 PM ASP.NET related
    Friday, September 20, 2019 6:54 AM

All replies

  • Hello,

    Ask your question here https://forums.asp.net/


    Please remember to mark the replies as answers if they help and unmarked them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.

    NuGet BaseConnectionLibrary for database connections.

    StackOverFlow
    profile for Karen Payne on Stack Exchange

    Friday, September 20, 2019 1:08 PM