asp.net read classic asp cookie - asp.net

I seem to be having a lot of issues reading a cookie from an old classic asp web application. we are slowly upgrading this web app to .net. The cookie holds some user information which also is used to tell the app that the person has authenticated successfully.
I try and read it like so:
Response.Cookies["mycookie"].Path = "/";
string strCookieText = Request.Cookies["mycookie"].Value;
Sometimes it seems to bring data back other times not but it is not consistent. I have also tried applying the same path when the cookie is created on the classic asp side but that seemed to really throw a wrench in the old app as then the classic asp side had a lot of challenges reading and finding the cookie.
So i figured i would create a function that would read in a classic asp page whos sole intent is to read the cookie. I don't like this method at all but I am out of ideas at this point. The issue here seems to be that it always comes back empty. I know there is data there however via fiddler and if i go to the actual site and hit the page. I am guessing this must be some pathing issue again perhaps or something like that that when i try and read it via .net it finds nothing.
here is my funciton that trys to read the page:
public CCookie validateCookie()
{
CCookie ckCCookie = new CCookie();
string strReadCookiePage = "";
strReadCookiePage = GetHtmlPage("HTTP://MYPAGE/readcookie.asp");
string[] strCarriageReturn = { "\n" }; //we are splitting on this character
string[] strPageSplit;
strPageSplit = strReadCookiePage.Split(strCarriageReturn, StringSplitOptions.RemoveEmptyEntries);
string strCookieLength = "-2";
foreach (string strValue in strPageSplit)
{
if (strCookieLength == "-1")
{
break;
}
if (strValue.Contains("<div id='arrayLength'>"))
{
strCookieLength = findStringValue(strValue, "<div id='arrayLength'>", "</div>");
}
if (strValue.Contains("<div id='VendorID'>"))
{
ckCCookie.UserVendorID = findStringValue(strValue, "<div id='VendorID'>", "</div>");
}
if (strValue.Contains("<div id='UserID'>"))
{
ckCCookie.UserID = Convert.ToInt64(findStringValue(strValue, "<div id='UserID'>", "</div>"));
}
if (strValue.Contains("<div id='LogonType'>"))
{
ckCCookie.LogonType = findStringValue(strValue, "<div id='LogonType'>", "</div>");
}
if (strValue.Contains("<div id='UserType'>"))
{
ckCCookie.UserType = findStringValue(strValue, "<div id='UserType'>", "</div>");
}
}
//not able to validate the cookie
if (strCookieLength == "-1")
{
//Response.Redirect("REDIRECT TO HAVE THEM LOG IN");
}
return ckCCookie;
}
why isn't this working do you guys think. I need this to consistently work. I know i could save state to dbase but I don't want to do this this way as I think i should be able to read this thing.
any ideas or thoughts on how to make this work?

Because of the way that cookies are stored they generally can't be shared between apps, like Classic ASP to ASP.NET.
I did find this article on MSDN that discusses solutions to the problem.
Personally, I would use a hidden field method to pass the cookie over, picking it up from the relevant control on the other side (ASP.NET).
-- EDIT --
Just so long as the hidden control resides in you form tags, you can try something like this (which is pretty much what ASP.NET does for it's __VIEWSTATE)...
<form id="myForm" method="post" action="myAspNetPage.aspx">
<all_the_controls_i_need_on_my_form>
...
...
</all_the_controls_i_need_on_my_form>
<input id="cookieData" name="cookieData" type="hidden" value="<%= cookieData %>" />
</form>
The VBScript...
Dim cookieData
cookieData = Request.Cookie("MyCookie")
Obviously if you have several cookies that you want to pass in this way then you may need to concatenate them for splitting later...
Const C_SEPERATOR = "|"
Dim cookieData
cookieData = _
"MyCookie1=" & Request.Cookie("MyCookie1") & C_SEPERATOR & _
"MyCookie2=" & Request.Cookie("MyCookie2") & C_SEPERATOR & _
"MyCookie3=" & Request.Cookie("MyCookie3") & C_SEPERATOR & _
"MyCookie4=" & Request.Cookie("MyCookie4")
The above example could obviously be automated by introducing a For..Next loop, but this is simply an example. Note, also, that I have simply taken for granted that none of your cookies use the vertical bar character (C_SEPERATOR); if they do, then you'll have to find an alternative character.
On the other side, in your ASP.NET app you can the read the value from the post data and split it up...
Private Const C_SEPARATOR = "|"
...
...
Dim tCook As String = Request.Form("cookieData")
Dim cookeiData() As String
If tCook<>"" Then cookieData = String.Split(tCook, C_SEPERATOR)
It's not the best solution - I'm sure that Lankymart will have something far better up his sleeve, but this will work.
PS: Apologies - I've just realised that I've done all this in VBScript. It should be pretty straightforward to convert to JScript, though.

Related

POST parameters in asp.net

I'm trying to get parameters received from a form, that were sent with method POST.
I don't know how it's called in asp, M$ loves to change stuff's names to mess with us. They come in HTTP body, while GET/QueryString parameters come in URL after the ? sign.
In PHP, "get patameters" are available in the $_GET array. In asp they are Request.QueryString["parameter1"].
"post patameters" are in $_POST, and I cant find it in asp. I hope I made it clear :p
To read the value from paramater1 contained inside the form data:
string paramater1 = Request.Form["paramater1"];
Note that if the form doesn't contain your variable, paramater1 will be null.
Suppose your querystring is something like this :
http://stackoverflow.com/questions.aspx?id=17844065&title=post-parameters-in-asp-net
if i am right then you are looking for this. Please note this is regarding ASP.Net, I have no idea about classic ASP. And this will not work on classic ASP, I believe.
You can use in cs,
if(Request["id"]!=null )
{
var id= Request["id"]; // gives you id as 17844065 string values
}
if(Request["title"]!=null )
{
var title= Request["title"]; // gives you title as string
}
Update :
NameValueCollection nvc = Request.Form;
string userName, password;
if (!string.IsNullOrEmpty(nvc["txtUserName"]))
{
userName = nvc["txtUserName"];
}
if (!string.IsNullOrEmpty(nvc["txtPassword"]))
{
password = nvc["txtPassword"];
}
Try Request.Params, it should contain all GET and/or POST parameters, Request.Form should contain only form parameters.

Unable to get property 'value' of undefined or null reference

I have registration form and button. OnClick - I call function on server side which make a validation of user's zip code at Database with Zipcodes. If validation passed successfully - user's data stored in Database (here I continue use server function). But if ZipCode does not match - I call Javascript function where I ask if user still wants to save his data to DB. and If yes - I save it using Ajax request. Problem is when I call Javascript function - firstly it should receive user's data on client side. But when reading data happens - I receive an error "Unable to get property 'value' of undefined or null reference". But user's data still exist at the form's fields. It seems that the data that read by the server from the form once - reset somewhere - and can not be read a second time on the client.
Here is my ASP Form
<body>
<form id="frmZipValidation" runat="server">
<div>
<asp:Label runat="server">Registration Form</asp:Label>
<asp:TextBox runat="server" ID="txtbxName"></asp:TextBox>
<asp:TextBox runat="server" ID="txtbxZipCode"></asp:TextBox>
<asp:DropDownList runat="server" ID="DDLCountry">
<asp:ListItem Text="Select country" Value="Select" Selected="True"></asp:ListItem>
<asp:ListItem Text="USA" Value="USA"></asp:ListItem>
<asp:ListItem Text="Canada" Value="Canada"></asp:ListItem>
</asp:DropDownList>
<asp:TextBox runat="server" ID="txtbxState"></asp:TextBox>
<asp:TextBox runat="server" ID="txtbxCity"></asp:TextBox>
<asp:Button runat="server" ID="btnSubmit" Text="Submit" OnClick="btnSubmit_Click"/>
</div>
</form>
</body>
Here is my Server Side
public partial class Default : System.Web.UI.Page
{
string Name;
string ZipCode;
string Country;
string State;
string City;
bool IsMatch;
Addresses dbAddresses = new Addresses();
User newUser;
protected void Page_Load(object sender, EventArgs e)
{
if (Request["Action"] != null && Request["Action"].Trim() != "")
{
if (Request["Action"] == "AddUser")
{
AddUser(Request["Name"], Request["ZipCode"], Request["Country"], Request["State"], Request["City"]);
}
}
}
private void AddUser(string UserName, string UserZip, string UserCountry, string UserState, string UserCity)
{
newUser = new User(UserName, UserZip, UserCountry, UserState, UserCity);
dbAddresses.Users.Add(newUser);
dbAddresses.SaveChanges();
}
protected void btnSubmit_Click(object sender, EventArgs e)
{
if (IsValid)
{
ZipCode = txtbxZipCode.Text;
Country = DDLCountry.Text;
State = txtbxState.Text;
City = txtbxCity.Text;
Name = txtbxName.Text;
IsMatch = false;
List<ZipCode> ZipC = (from z in dbAddresses.Zips
where z.Zip == ZipCode
select z).ToList();
//If ZipCode entered by client do not exists at Database return false
if (!ZipC.Any())
{
IsMatch = false;
}
else
{
for (int i = 0; i < ZipC.Count; i++)
{
if (ZipC[i].Country.ToString() == Country)
{
if (ZipC[i].State.ToString() == State)
{
if (ZipC[i].City.ToString() == City)
{
AddUser(Name, ZipCode, Country, State, City);
//Message to the user that all saved successfully
Page.ClientScript.RegisterClientScriptBlock(typeof(Page), "1", "<script>alert('Your data was saved successfully!');</script>");
IsMatch = true;
break;
}
else
{
IsMatch = false;
break;
}
}
else
{
IsMatch = false;
break;
}
}
else
{
IsMatch = false;
break;
}
}
}
//If user's data are not match, then go to JS client code where - If user wants in any case to save data - make it using AJAX request
if (!IsMatch)
{
string clientScript = "AjaxRequestSaveToDB();";
this.Page.ClientScript.RegisterStartupScript(this.GetType(), "MyClientScript", clientScript);
}
}
}
}
And here is Javascript:
function AjaxRequestSaveToDB()
{
var SaveData = confirm('Zip/Postal code doesn’t match region. Are you sure you want to save this data?');
if (SaveData)
{
var UserName = document.getElementById('txtbxName').value;
var UserZipCode = document.getElementById('txtbxZipCode').value;
var UserCountry = document.getElementById('DDLCountry').value;
var USerState = document.getElementById('txtbxState').value;
var UserCity = document.getElementById('txtbxCity').value;
SendDataToServer('AddUser', UserName, UserZipCode, UserCountry, USerState, UserCity);
alert("You data was saved successfully!");
}
else { alert('Not saved');
}
}
}
function SendDataToServer(RequestType, Name, ZipCode, Country, State, City)
{
var xmlHttp = getXmlHttp();
var Url = "Default.aspx?Action=" + escape(RequestType)
+ "&Name=" + escape(Name)
+ "&ZipCode=" + escape(ZipCode)
+ "&Country=" + escape(Country)
+ "&State=" + escape(State)
+ "&City=" + escape(City);
xmlHttp.open("GET", Url, true);
xmlHttp.send();
}
A short book about Client-Server Communications using "Custom" AJAX requests.
In ASP.net programming (almost) every time the client interacts with the server, the client sends all of its information to the server and then throws out its old content and replaces it with the response the client received from the server. So the problem you were running into is that your asp:button on the client machine was sending information to your .aspx page on the server and the server was interpreting the information, realizing something was wrong and telling the client it should ask the user for more information but throw out all the information that had been previously entered.
The best way that I have found to get around this problem is to use what I call "custom AJAX requests." Basically this means that we write a string of XML and send it to an ASP handler page which is set up to accept the XML string and do something with it. In my travels I have slimmed this down to basically 3 parts. The first is the user interface which contains all of the markup and CSS(and validation), the second is the JavaScript file that contains all of the data gathering and the actual AJAX request and lastly there is the ashx file that handles the request from the client.
So to start you will need to set up your user interface. Something along the lines of:
<body>
<form id="frmZipValidation" runat="server">
<div>
<div class="label">Registration Form<div>
<asp:TextBox ID="txtbxName" class="txtbxName" ClientIDMode="Static" runat="server"></asp:TextBox>
<asp:TextBox ID="txtbxZipCode" class="txtbxZipCode" ClientIDMode="Static" runat="server" ></asp:TextBox>
<asp:DropDownList ID="DDLCountry" class="DDLCountry" ClientIDMode="Static" runat="server" >
<asp:ListItem Text="Select country" Value="Select" Selected="True"></asp:ListItem>
<asp:ListItem Text="USA" Value="USA"></asp:ListItem>
<asp:ListItem Text="Canada" Value="Canada"></asp:ListItem>
</asp:DropDownList>
<asp:TextBox ID="txtbxState" class="txtbxState" ClientIDMode="Static" runat="server" ></asp:TextBox>
<asp:TextBox ID="txtbxCity" class="txtbxCity" ClientIDMode="Static" runat="server" ></asp:TextBox>
<input id="btnSubmit" class="btnSubmit" type="button" value="Save" onclick="SubmitForm()" />
</div>
</form>
</body>
Couple things to note with this:
The button to submit the form is NOT an ASP button but a HTML button.
All of the input controls are ASP controls but they have the ClientIDMode set to Static, this will only work in .NET 4.0 or higher.
We set the class to the same thing as the ID in case we aren't using .NET 4.0 or higher. Any CSS classes that you want to also add to the control can be added after the dummy ID class.(for my examples I'm assuming you are in .NET 4.0 but I can easily switch them to work without the ClientIDMode attribute if you need)
The second piece to the puzzle is the JavaScript. There are a couple ways that we can accomplish what we need. The first is by using vanilla JS without the help of any plugins or external libraries. This saves a very small amount of processing time, a marginal amount of loading time and can accomplish everything we ask of it. But, if we include an external library, JQuery, and plugin, JQuery Validation, then we can make our lives a whole heck of a lot easier during the programming phase by reducing the amount of code we have to write by a factor of about 10. And if we are really concerned about the load times then we can use the client cache to store the external libraries so that they only have to download them once. So whether or not you decide to use any external JavaScript libraries is up to what your project needs but since you are only concerned with validating that the zip code is not empty I will not use any JQuery but I just thought it would be worth mentioning because of how streamlined it makes the process.
Once you are ready to submit your form your first step will be to validate that the zipcode is valid. You can do this a couple ways depending on how in depth you want to get. The quickest check would just be to verify that the zip code text box is not empty when the button is clicked. So to do that we would just need to do:
function SubmitForm() { //This will be assigned as the click handler on your button in your HTML
if (document.getElementById('txtbxZipCode').value != null && document.getElementById('txtbxZipCode').value != '') {
Save('YourHandler', GetQueryString, GetXmlString, SuccessHandler, FailureHandler);
} else {
//Your user needs to know what went wrong...
}
}
So, down to the meat and potatoes of this whole situation. The AJAX request. I've come up with a reusable function that handles the entire AJAX request that looks like:
function Save(handlerName, GetQueryString, GetXmlString, SuccessHandler, FailureHandler) {
// Date.GetTime gets the number of milliseconds since 1 January 1970, so we divide by 1000 to get the seconds.
end = (new Date().getTime() / 1000) + 30;
//This variable is the actual AJAX request. This object works for IE8+ but if you want backwards compatability for earlier versions you will need a different object which I can dig up for you if you need.
var xmlhttp = new XMLHttpRequest();
//This is the function that fires everytime the status of the request changes.
xmlhttp.onreadystatechange = function () {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
//Get all the headers to determine whether or not the request was successful. This is a header you will need to add to the response manually.
var xx = xmlhttp.getResponseHeader("Success");
//the object xx will be a string that you designate. I chose to use True as the indicator that it was successful because it was intuitive.
var x1 = xx.trim();
if (x1 != undefined && x1 == 'True' && (new Date().getTime() / 1000) < end) {
//If the response was successful and the timeout hasn't elapsed then we get the XML from the response and call the success handler
var xmlResponse = xmlhttp.responseXML;
SuccessHandler(sender, xmlResponse);
} else if ((new Date().getTime() / 1000) < end) {
//If the response was not successful and the timeout hasn't elapsed then we get the XML from the response and call the failure handler
var xmlResponse = xmlhttp.responseXML;
FailureHandler(sender, xmlResponse);
} //If the request was successful
} //If the readystate is 4 and the status is 200
} //OnReadyStateChanged function
//This gets the query string to be added to the url
var varString = GetQueryString();
//Build XML string to send to the server
var xmlString = GetXmlString();
//Open the request using the handler name passed in and the querystring we got from the function passed in
xmlhttp.open("POST", "../RequestHandlers/" + handlerName + ".ashx" + varString, true);
//This tells the handler that the content of the request is XML
xmlhttp.setRequestHeader("Content-Type", "text/xml");
//Send the request using the XML we got from the other function passed in.
xmlhttp.send(xmlString);
}
This function has a built in timeout which makes it so that if the server takes more than 30 seconds to respond to a request then any response that the client receives is ignored. For my implementations this is combined with another function that displays something to the user to tell them that the website is working on their request and if the time out elapses it tells them that a time out occurred.
The second thing this function does is it assumes that all handlers will be in a folder next to the root of your website named RequestHandlers. I use this set up just to consolidate all of my handler files but you can really change where it is looking to wherever you want.
The function itself takes in a string and four function pointers. The string represents the name of the handler that will be waiting to interpret the request, the four function pointers all have very specific jobs.
The first function pointer is GetQueryString this represents a function you will have to write that will append any variables that you deem necessary to the end of the URL being posted back to. This site gives a pretty accurate explanation of what the query string should be used for. For me a common GetQueryString function looks something like:
function GetPaymentQueryString() {
var varString = '';
varString = "?CCPayment=True";
return varString;
}
The second function pointer, GetXMLString, is used to create the XML string(go figure...) that will be sent to the handler page that we are posting back to. This string will represent the bulk of the request. Everything that should not be shown to anyone snooping your requests should be sent as an XML string, if you are really paranoid you can send it as an encrypted XML string but that's not, strictly speaking, necessary. It all depends on what you are sending, if its complete credit card information then, yeah, maybe you would want to consider it, but if its first and last names then encrypting it would be overkill.
A common GetXMLString function might look like:
function GetPaymentXmlString() {
var xmlString = '';
xmlString = '<?xml version="1.0" encoding="UTF-8"?><Address><ZipCode>' + document.getElementById('txtbxZipCode').value + '</ZipCode></Address>';
return xmlString;
}
The important part of that function is to get your XML right. The first tag is pretty universal and should be fine to use in most situations and then after that its all just matching the tags up. I left out a lot of your fields to save space.
The last two function pointers are what you will want to call if everything goes as planned and if something fails respectively. The way that I normally handle successful requests is to hide the inputs as a whole(usually by putting them inside of their own div section) and displaying a confirmation message of some sort. Failed requests can be a bit trickier because you have to tell the user why they failed. The way that I do that is by having a dummy div section above everything else on the page with some sort of special CSS attached to it that makes the div stand out in some way and if the request fails then I send a string of text from the server with my best guess of why it failed and assign it to the be displayed in the div section. How you decide to display the results to the user is obviously all dictated by the project itself. Since what you do when it succeeds or fails is basically on a project by project basis I can't really give a good generic example of what you should do so for this part you are on your own.
Now that we have those pieces in place, the last piece to make is the handler.
Basically for all intents and purposes a handler is basically an ASPX webpage with nothing on it. So the HTML that makes up your handler pages, which have the extension .ashx, will look like:
<%# WebHandler Language="VB" CodeBehind="YourHandler.ashx.cs" Class="YourHandler" %>
And that's it. There should be no other markup in your actual .ashx file. Obviously the name of the handler will change depending on what you are doing.
The code behind when creating an ashx file by default will be a class that contains a single function named ProcessRequest. Basically you can treat this function as a sort of "request received" event. So in your case you would move the content of your btnSubmit_Click function to the ProcessRequest function in the ashx file. You can add any properties or other functions that you want but the ProcessRequest function must be present for the handler to work as far as I know.
One extra step that you will need to do is to get the information from the XML that was sent to your handler and also tell the response that you will be sending XML back to the client.
So to get the XML from the request you will need to do:
IO.StreamReader textReader = New IO.StreamReader(context.Request.InputStream);
context.Request.InputStream.Seek(0, IO.SeekOrigin.Begin);
textReader.DiscardBufferedData();
XDocument xml = XDocument.Load(textReader);
String zip = xml.Elements("Address").Elements("ZipCode").FirstOrDefault().Value;
In order to send XML back to the client you will need to add a couple headers to the response and you accomplish that by adding(I think this is the correct way to implement an interface in C# not positive on this point though):
class YourHandler : System.Web.IHttpHandler, System.Web.SessionState.IReadOnlySessionState
under your class definition and:
context.Response.ContentType = "text/xml";
context.Response.ContentEncoding = System.Text.Encoding.UTF8;
context.Response.Cache.SetCacheability(HttpCacheability.NoCache);
context.Response.Cache.SetAllowResponseInBrowserHistory(True);
to the beginning of your ProcessRequest function. Those six lines tell the client it will be receiving XML and not to cache any of the response which will ensure that your clients always see the most up-to-date content.
So. There it is. You should now have the framework to validate user input, create an AJAX request, send the request to a custom handler, accept XML from the client, write XML to the client and display the res-...I knew I forgot something...
What is the client supposed to do with the XML it gets from the server? throw it at the wall and see what sticks? No that won't work. You'll need a way to interpret the XML on the client side. Luckily the XMLHttpRequest object has been written to make this task a lot easier than it sounds.
You may have noticed that I set up my success and failure handlers to take a sender object and an XML object. The sender is really overkill and can be ignored(or removed) for this example to work fine. The XML object is what we are concerned with for now. Before we even get into the client side I must mention that you will have to go through the same process on the server side as you did on the client side and manually write your XML string including all the values you want the client to know about. For this example I'm going to assume you want to display a FriendlyMessage to the user. To write the response to the client you will do something like:
using (System.Xml.XmlTextWriter writer = new System.Xml.XmlTextWriter(context.Response.Output)) {
context.Response.AddHeader("Success", true);
System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
doc.LoadXml("<?xml version='1.0' encoding='UTF-8'?><Response><FriendlyMessage>" + Message + "</FriendlyMessage></Response>");
doc.WriteTo(writer);
writer.Flush();
writer.Close();
}
On the client side to get the FriendlyMessage from the XML you will need to do:
xml.getElementsByTagName("FriendlyMessage")[0].childNodes[0].nodeValue
Now this line makes a few assumptions. Like, you may want to add some checks in to make sure xml.getElementsByTagName("FriendlyMessage") actually has children before trying to evaluate them. Those sorts of checks are up to your discretion.
This time I think I've actually covered all the steps. I hope my "little" guide helps you and I didn't bore you too much. I apologize for the length but its sort of a process so getting it right takes a few steps. Once you get the base line in place and working it really lends itself to any situation. This layout also makes your user experience much better than having them wait for full trips to the server each time.
I sincerely hope this helps you get your project done and that I haven't skipped a step or something equally as embarrassing...

How to Get the ConnectionString that the Membership Provider is using?

... and not by reading it from the config file! Nor inferring it from anyplace other than be reading exactly what the Membership Provider is itself using. Call me paranoid.
The first data access in my application is an access to the membership provider. The vast majority of connectivity issues have been where the application is deployed to staging or production with a connection string from development, so I'd like to change this:
MembershipUser me = Membership.GetUser();
to this:
MembershipUser me;
try
{
me = Membership.GetUser();
}
catch ( SqlException E )
{
Response.Write( "SQL Error " + E.Message + ".<br />" );
Response.Write( "Connection String: " + Membership.Provider.WHAT? + "<br />" );
}
Seems so obvious, but every reference I find instructs me to use the ConfigurationManager, which is what I specifically don't want to do. Although I concede that such may be my only option, and a satisfactory one at that.
I'm perfectly willing to accept the possibility that my question is on par with this:
int i;
try
{
i = 42;
}
catch ( Exception e )
{
Response.Write( "Error assigning literal to integer." );
}
If this is the case, please comment accordingly.
I don't believe there is a direct property that you can use that will give you the connection information. One thing you could do though is subclass your chosen membership provider and implement your own properties to give you the info.
It's generally considered a bad idea to surface connection strings in the UI (i.e. poor security) which is why you won't find readily available properties to pass on the value from classes that have read it from the config file.
You may want to consider addressing the root cause of the problem which is related to deployment. This problem is easily solved by using different configuration files for development, staging and production. Visual Studio has built-in support for automatically managing the deployment of the appropriate config file. Full details here:
http://blogs.msdn.com/b/webdevtools/archive/2009/05/04/web-deployment-web-config-transformation.aspx
Hi Here is a way to get connection string from or by the specified Provider Name (ex MySQL provider).
using MySql.Data.MySqlClient;
using MySql.Data;
using MySql.Web.Security;
using System.Collections.Specialized;
using System.Reflection;
void SomeFunction()
{
Type t = Membership.Provider.GetType();
FieldInfo fi = null;
while (fi == null && t != null)
{
fi = t.GetField("connectionString", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
t = t.BaseType;
}
MySql.Web.Security.MySQLMembershipProvider a =(MySql.Web.Security.MySQLMembershipProvider)Membership.Provider;
string Connection_String_Value= fi.GetValue(a).ToString();
}
By replace 'connectionString' with other Non-Public field name You
can Access its Value too.
By replacing Provider(default) with
Membership.Providers["Name_Of_Your_Provider"] you can get its
connection string too.

Flex 3 - how to support HTTP Authentication URLRequest?

I have a Flex file upload script that uses URLRequest to upload files to a server. I want to add support for http authentication (password protected directories on the server), but I don't know how to implement this - I assume I need to extend the class somehow, but on how to I'm a little lost.
I tried to modify the following (replacing HTTPService with URLRequest), but that didn't work.
private function authAndSend(service:HTTPService):void{
var encoder:Base64Encoder = new Base64Encoder();
encoder.encode("someusername:somepassword");
service.headers = {Authorization:"Basic " + encoder.toString()};
service.send();
}
I should point out that I'm not knowledgeable when it comes to ActionScript / Flex, although I have managed to successfully modify the upload script somewhat.
[Edit] - here is an update of my progress, based on the answer below, although I still cannot get this to work:
Thank you for your assistance. I've tried to implement your code but I've not had any luck.
The general behaviour I'm experiencing when dealing with HTTP authenticated locations is that with IE7 all is well but in Firefox when I attempt to upload a file to the server it displays an HTTP authentication prompt - which even if given the correct details, simply stalls the upload process.
I believe the reason IE7 is ok is down to the the session / authentication information being shared by the browser and the Flash component - however, in Firefox this is not the case and I experience the above behaviour.
Here is my updated upload function, incorporating your changes:
private function pergress():void
{
if (fileCollection.length == 0)
{
var urlString:String = "upload_process.php?folder="+folderId+"&type="+uploadType+"&feid="+formElementId+"&filetotal="+fileTotal;
if (ExternalInterface.available)
{
ExternalInterface.call("uploadComplete", urlString);
}
}
if (fileCollection.length > 0)
{
fileTotal++;
var urlRequest:URLRequest = new URLRequest("upload_file.php?folder="+folderId+"&type="+uploadType+"&feid="+formElementId+"&obfuscate="+obfuscateHash+"&sessidpass="+sessionPass);
urlRequest.method = URLRequestMethod.POST;
urlRequest.data = new URLVariables("name=Bryn+Jones");
var encoder:Base64Encoder = new Base64Encoder();
encoder.encode("testuser:testpass");
var credsHeader:URLRequestHeader = new URLRequestHeader("Authorization", "Basic " + encoder.toString());
urlRequest.requestHeaders.push(credsHeader);
file = FileReference(fileCollection.getItemAt(0));
file.addEventListener(Event.COMPLETE, completeHandler);
file.addEventListener(HTTPStatusEvent.HTTP_STATUS, onHTTPStatus);
file.addEventListener(ProgressEvent.PROGRESS, onUploadProgress);
file.upload(urlRequest);
}
}
As stated above, I seem to be experiencing the same results with or without the amendments to my function.
Can I ask also where the crossdomain.xml should be located - as I do not currently have one and am unsure where to place it.
The syntax is a little different for URLRequest, but the idea's the same:
private function doWork():void
{
var req:URLRequest = new URLRequest("http://yoursite.com/yourservice.ext");
req.method = URLRequestMethod.POST;
req.data = new URLVariables("name=John+Doe");
var encoder:Base64Encoder = new Base64Encoder();
encoder.encode("yourusername:yourpassword");
var credsHeader:URLRequestHeader = new URLRequestHeader("Authorization", "Basic " + encoder.toString());
req.requestHeaders.push(credsHeader);
var loader:URLLoader = new URLLoader();
loader.load(req);
}
A couple of things to keep in mind:
Best I can tell, for some reason, this only works where request method is POST; the headers don't get set with GET requests.
Interestingly, it also fails unless at least one URLVariables name-value pair gets packaged with the request, as indicated above. That's why many of the examples you see out there (including mine) attach "name=John+Doe" -- it's just a placeholder for some data that URLRequest seems to require when setting any custom HTTP headers. Without it, even a properly authenticated POST request will also fail.
Apparently, Flash player version 9.0.115.0 completely blocks all Authorization headers (more information on this one here), so you'll probably want to keep that in mind, too.
You'll almost surely have to modify your crossdomain.xml file to accommodate the header(s) you're going to be sending. In my case, I'm using this, which is a rather wide-open policy file in that it accepts from any domain, so in your case, you might want to limit things a bit more, depending on how security-conscious you are.
crossdomain.xml:
<?xml version="1.0"?>
<cross-domain-policy>
<allow-access-from domain="*" />
<allow-http-request-headers-from domain="*" headers="Authorization" />
</cross-domain-policy>
... and that seems to work; more information on this one is available from Adobe here).
The code above was tested with Flash player 10 (with debug & release SWFs), so it should work for you, but I wanted to update my original post to include all this extra info in case you run into any issues, as the chances seem (sadly) likely that you will.
Hope it helps! Good luck. I'll keep an eye out for comments.
The FileReference.upload() and FileReference.download() methods do not support the URLRequest.requestHeaders parameter.
http://livedocs.adobe.com/flex/2/langref/flash/net/URLRequest.html
If you want to upload a file, you just need to send the correct headers and the content of file using URLRequest via UploadPostHelper class. This works 100%, i am using this class to upload generated images and CSV files, but you could upload any kind of file.
This class simply prepares the request with headers and content as if you would be uploading the file from a html form.
http://code.google.com/p/as3asclublib/source/browse/trunk/net/UploadPostHelper.as?r=118
_urlRequest = new URLRequest(url);
_urlRequest.data = "LoG";
_urlRequest.method = URLRequestMethod.POST;
_urlRequest.requestHeaders.push(new URLRequestHeader("X-HTTP-Code-Override", "true"));
_urlRequest.requestHeaders.push(new URLRequestHeader("pragma", "no-cache"));
initCredentials();
_loader.dataFormat = URLLoaderDataFormat.BINARY;
//this creates a security problem, putting the content type in the headers bypasses this problem
//_urlRequest.contentType = 'multipart/form-data; boundary=' + UploadPostHelper.getBoundary();
_urlRequest.requestHeaders.push( new URLRequestHeader( 'Cache-Control', 'no-cache' ) );
_urlRequest.requestHeaders.push(new URLRequestHeader('Content-Type', 'multipart/form-data; boundary=' + UploadPostHelper.getBoundary()));
_urlRequest.data = UploadPostHelper.getPostData("file.csv", param[1]);
_loader.load(_urlRequest);
I'm not sure about this but have you tried adding username:password# to the beginning of your url?
"http://username:password#yoursite.com/yourservice.ext"
var service : HTTPService = new HTTPService ();
var encoder:Base64Encoder = new Base64Encoder();
encoder.insertNewLines = false;
encoder.encode("user:password");
service.headers = {Authorization:"Basic " + encoder.toString()};
service.method = HTTPRequestMessage.POST_METHOD;
service.request = new URLVariables("name=John+Doe");
service.addEventListener(FaultEvent.FAULT,error_handler );
service.addEventListener(ResultEvent.RESULT,result_handler);
service.url = 'http://blah.blah.xml?'+UIDUtil.createUID();
service.send();
Seemingly similar problem was solved here. I urge you to also check the Flexcoders post linked to in the first post.
The problem was that FireFox uses a separate browser window instance to send the file upload request. The solution is to manually attach the session id to the request url. The session id is not attached as a regular GET variable, but with a semicolon (the reason for this syntax is unknown to me).
Flash is very limited in terms of what sort of headers you can pass with an http request (and it changes between browsers and OSes). If you get this to work on one browser/OS, make sure you test it on the others.
The best thing to do is not mess with HTTP headers.
We have the same issue (uploading to Picasa Web Albums from flash) and post through a proxy on our server. We pass the extra headers through as post parameters and our proxy does the right thing.
"http://username:password#yoursite.com/yourservice.ext"
This doesn't work in IE (http://www.theregister.co.uk/2004/01/30/ms_drop_authentication_technique/) and doesn't seem to work in Chrome either.
probably not usable in Flash
Here is a work-around when using ASP.Net based in part on the work here.
I built a component that dynamically writes Flex objects to the page so they can be used in UpdatePanels. Message me if you want they code. To solve the above problem in pages where authentication cookies will need to be sent by URLRequest, I add the values in as flashVars.
This code only works in my object, but you get the idea
Dictionary<string, string> flashVars = new Dictionary<string, string>();
flashVars.Add("auth", Request.Cookies["LOOKINGGLASSFORMSAUTH"].Value);
flashVars.Add("sess", Request.Cookies["ASP.NET_SessionId"].Value);
myFlexObject.SetFlashVars(flashVars);
Then in the Flex Object, check for the params
if (Application.application.parameters.sess != null)
sendVars.sess= Application.application.parameters.sess;
if (Application.application.parameters.auth != null)
sendVars.au= Application.application.parameters.auth;
request.data = sendVars;
request.url = url;
request.method = URLRequestMethod.POST;
Finally stuff the cookies in on global.asax BeginRequest
if (Request.RequestType=="POST" && Request.Path.EndsWith("upload.aspx"))
{
try
{
string session_param_name = "sess";
string session_cookie_name = "ASP.NET_SESSIONID";
string session_value = Request.Form[session_param_name]; // ?? Request.QueryString[session_param_name];
if (session_value != null) { UpdateCookie(session_cookie_name, session_value); }
}
catch (Exception) { }
try
{
string auth_param_name = "au";
string auth_cookie_name = FormsAuthentication.FormsCookieName;
string auth_value = Request.Form[auth_param_name];// ?? Request.QueryString[auth_param_name];
if (auth_value != null) { UpdateCookie(auth_cookie_name, auth_value); }
}
catch (Exception) { }
}
Hope this help someone avoid the 6 hours I just spent addressing this. Adobe has closed the issue as unresolvable, so this was my last resort.

Response.Redirect with POST instead of Get?

We have the requirement to take a form submission and save some data, then redirect the user to a page offsite, but in redirecting, we need to "submit" a form with POST, not GET.
I was hoping there was an easy way to accomplish this, but I'm starting to think there isn't. I think I must now create a simple other page, with just the form that I want, redirect to it, populate the form variables, then do a body.onload call to a script that merely calls document.forms[0].submit();
Can anyone tell me if there is an alternative? We might need to tweak this later in the project, and it might get sort of complicated, so if there was an easy we could do this all non-other page dependent that would be fantastic.
Anyway, thanks for any and all responses.
Doing this requires understanding how HTTP redirects work. When you use Response.Redirect(), you send a response (to the browser that made the request) with HTTP Status Code 302, which tells the browser where to go next. By definition, the browser will make that via a GET request, even if the original request was a POST.
Another option is to use HTTP Status Code 307, which specifies that the browser should make the redirect request in the same way as the original request, but to prompt the user with a security warning. To do that, you would write something like this:
public void PageLoad(object sender, EventArgs e)
{
// Process the post on your side
Response.Status = "307 Temporary Redirect";
Response.AddHeader("Location", "http://example.com/page/to/post.to");
}
Unfortunately, this won't always work. Different browsers implement this differently, since it is not a common status code.
Alas, unlike the Opera and FireFox developers, the IE developers have never read the spec, and even the latest, most secure IE7 will redirect the POST request from domain A to domain B without any warnings or confirmation dialogs! Safari also acts in an interesting manner, while it does not raise a confirmation dialog and performs the redirect, it throws away the POST data, effectively changing 307 redirect into the more common 302.
So, as far as I know, the only way to implement something like this would be to use Javascript. There are two options I can think of off the top of my head:
Create the form and have its action attribute point to the third-party server. Then, add a click event to the submit button that first executes an AJAX request to your server with the data, and then allows the form to be submitted to the third-party server.
Create the form to post to your server. When the form is submitted, show the user a page that has a form in it with all of the data you want to pass on, all in hidden inputs. Just show a message like "Redirecting...". Then, add a javascript event to the page that submits the form to the third-party server.
Of the two, I would choose the second, for two reasons. First, it is more reliable than the first because Javascript is not required for it to work; for those who don't have it enabled, you can always make the submit button for the hidden form visible, and instruct them to press it if it takes more than 5 seconds. Second, you can decide what data gets transmitted to the third-party server; if you use just process the form as it goes by, you will be passing along all of the post data, which is not always what you want. Same for the 307 solution, assuming it worked for all of your users.
You can use this aproach:
Response.Clear();
StringBuilder sb = new StringBuilder();
sb.Append("<html>");
sb.AppendFormat(#"<body onload='document.forms[""form""].submit()'>");
sb.AppendFormat("<form name='form' action='{0}' method='post'>",postbackUrl);
sb.AppendFormat("<input type='hidden' name='id' value='{0}'>", id);
// Other params go here
sb.Append("</form>");
sb.Append("</body>");
sb.Append("</html>");
Response.Write(sb.ToString());
Response.End();
As result right after client will get all html from server the event onload take place that triggers form submit and post all data to defined postbackUrl.
HttpWebRequest is used for this.
On postback, create a HttpWebRequest to your third party and post the form data, then once that is done, you can Response.Redirect wherever you want.
You get the added advantage that you don't have to name all of your server controls to make the 3rd parties form, you can do this translation when building the POST string.
string url = "3rd Party Url";
StringBuilder postData = new StringBuilder();
postData.Append("first_name=" + HttpUtility.UrlEncode(txtFirstName.Text) + "&");
postData.Append("last_name=" + HttpUtility.UrlEncode(txtLastName.Text));
//ETC for all Form Elements
// Now to Send Data.
StreamWriter writer = null;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = postData.ToString().Length;
try
{
writer = new StreamWriter(request.GetRequestStream());
writer.Write(postData.ToString());
}
finally
{
if (writer != null)
writer.Close();
}
Response.Redirect("NewPage");
However, if you need the user to see the response page from this form, your only option is to utilize Server.Transfer, and that may or may not work.
Something new in ASP.Net 3.5 is this "PostBackUrl" property of ASP buttons. You can set it to the address of the page you want to post directly to, and when that button is clicked, instead of posting back to the same page like normal, it instead posts to the page you've indicated. Handy. Be sure UseSubmitBehavior is also set to TRUE.
This should make life much easier.
You can simply use Response.RedirectWithData(...) method in your web application easily.
Imports System.Web
Imports System.Runtime.CompilerServices
Module WebExtensions
<Extension()> _
Public Sub RedirectWithData(ByRef aThis As HttpResponse, ByVal aDestination As String, _
ByVal aData As NameValueCollection)
aThis.Clear()
Dim sb As StringBuilder = New StringBuilder()
sb.Append("<html>")
sb.AppendFormat("<body onload='document.forms[""form""].submit()'>")
sb.AppendFormat("<form name='form' action='{0}' method='post'>", aDestination)
For Each key As String In aData
sb.AppendFormat("<input type='hidden' name='{0}' value='{1}' />", key, aData(key))
Next
sb.Append("</form>")
sb.Append("</body>")
sb.Append("</html>")
aThis.Write(sb.ToString())
aThis.End()
End Sub
End Module
Thought it might interesting to share that heroku does this with it's SSO to Add-on providers
An example of how it works can be seen in the source to the "kensa" tool:
https://github.com/heroku/kensa/blob/d4a56d50dcbebc2d26a4950081acda988937ee10/lib/heroku/kensa/post_proxy.rb
And can be seen in practice if you turn of javascript. Example page source:
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Heroku Add-ons SSO</title>
</head>
<body>
<form method="POST" action="https://XXXXXXXX/sso/login">
<input type="hidden" name="email" value="XXXXXXXX" />
<input type="hidden" name="app" value="XXXXXXXXXX" />
<input type="hidden" name="id" value="XXXXXXXX" />
<input type="hidden" name="timestamp" value="1382728968" />
<input type="hidden" name="token" value="XXXXXXX" />
<input type="hidden" name="nav-data" value="XXXXXXXXX" />
</form>
<script type="text/javascript">
document.forms[0].submit();
</script>
</body>
</html>
PostbackUrl can be set on your asp button to post to a different page.
if you need to do it in codebehind, try Server.Transfer.
#Matt,
You can still use the HttpWebRequest, then direct the response you receive to the actual outputstream response, this would serve the response back to the user. The only issue is that any relative urls would be broken.
Still, that may work.
I suggest building an HttpWebRequest to programmatically execute your POST and then redirect after reading the Response if applicable.
Here's what I'd do :
Put the data in a standard form (with no runat="server" attribute) and set the action of the form to post to the target off-site page.
Before submitting I would submit the data to my server using an XmlHttpRequest and analyze the response. If the response means you should go ahead with the offsite POSTing then I (the JavaScript) would proceed with the post otherwise I would redirect to a page on my site
In PHP, you can send POST data with cURL. Is there something comparable for .NET?
Yes, HttpWebRequest, see my post below.
The GET (and HEAD) method should never be used to do anything that has side-effects. A side-effect might be updating the state of a web application, or it might be charging your credit card. If an action has side-effects another method (POST) should be used instead.
So, a user (or their browser) shouldn't be held accountable for something done by a GET. If some harmful or expensive side-effect occurred as the result of a GET, that would be the fault of the web application, not the user. According to the spec, a user agent must not automatically follow a redirect unless it is a response to a GET or HEAD request.
Of course, a lot of GET requests do have some side-effects, even if it's just appending to a log file. The important thing is that the application, not the user, should be held responsible for those effects.
The relevant sections of the HTTP spec are 9.1.1 and 9.1.2, and 10.3.
Typically, all you'll ever need is to carry some state between these two requests. There's actually a really funky way to do this which doesn't rely on JavaScript (think <noscript/>).
Set-Cookie: name=value; Max-Age=120; Path=/redirect.html
With that cookie there, you can in the following request to /redirect.html retrieve the name=value info, you can store any kind of information in this name/value pair string, up to say 4K of data (typical cookie limit). Of course you should avoid this and store status codes and flag bits instead.
Upon receiving this request you in return respond with a delete request for that status code.
Set-Cookie: name=value; Max-Age=0; Path=/redirect.html
My HTTP is a bit rusty I've been going trough RFC2109 and RFC2965 to figure how reliable this really is, preferably I would want the cookie to round trip exactly once but that doesn't seem to be possible, also, third-party cookies might be a problem for you if you are relocating to another domain. This is still possible but not as painless as when you're doing stuff within your own domain.
The problem here is concurrency, if a power user is using multiple tabs and manages to interleave a couple of requests belonging to the same session (this is very unlikely, but not impossible) this may lead to inconsistencies in your application.
It's the <noscript/> way of doing HTTP round trips without meaningless URLs and JavaScript
I provide this code as a prof of concept: If this code is run in a context that you are not familiar with I think you can work out what part is what.
The idea is that you call Relocate with some state when you redirect, and the URL which you relocated calls GetState to get the data (if any).
const string StateCookieName = "state";
static int StateCookieID;
protected void Relocate(string url, object state)
{
var key = "__" + StateCookieName + Interlocked
.Add(ref StateCookieID, 1).ToInvariantString();
var absoluteExpiration = DateTime.Now
.Add(new TimeSpan(120 * TimeSpan.TicksPerSecond));
Context.Cache.Insert(key, state, null, absoluteExpiration,
Cache.NoSlidingExpiration);
var path = Context.Response.ApplyAppPathModifier(url);
Context.Response.Cookies
.Add(new HttpCookie(StateCookieName, key)
{
Path = path,
Expires = absoluteExpiration
});
Context.Response.Redirect(path, false);
}
protected TData GetState<TData>()
where TData : class
{
var cookie = Context.Request.Cookies[StateCookieName];
if (cookie != null)
{
var key = cookie.Value;
if (key.IsNonEmpty())
{
var obj = Context.Cache.Remove(key);
Context.Response.Cookies
.Add(new HttpCookie(StateCookieName)
{
Path = cookie.Path,
Expires = new DateTime(1970, 1, 1)
});
return obj as TData;
}
}
return null;
}
Copy-pasteable code based on Pavlo Neyman's method
RedirectPost(string url, T bodyPayload) and GetPostData() are for those who just want to dump some strongly typed data in the source page and fetch it back in the target one.
The data must be serializeable by NewtonSoft Json.NET and you need to reference the library of course.
Just copy-paste into your page(s) or better yet base class for your pages and use it anywhere in you application.
My heart goes out to all of you who still have to use Web Forms in 2019 for whatever reason.
protected void RedirectPost(string url, IEnumerable<KeyValuePair<string,string>> fields)
{
Response.Clear();
const string template =
#"<html>
<body onload='document.forms[""form""].submit()'>
<form name='form' action='{0}' method='post'>
{1}
</form>
</body>
</html>";
var fieldsSection = string.Join(
Environment.NewLine,
fields.Select(x => $"<input type='hidden' name='{HttpUtility.UrlEncode(x.Key)}' value='{HttpUtility.UrlEncode(x.Value)}'>")
);
var html = string.Format(template, HttpUtility.UrlEncode(url), fieldsSection);
Response.Write(html);
Response.End();
}
private const string JsonDataFieldName = "_jsonData";
protected void RedirectPost<T>(string url, T bodyPayload)
{
var json = JsonConvert.SerializeObject(bodyPayload, Formatting.Indented);
//explicit type declaration to prevent recursion
IEnumerable<KeyValuePair<string, string>> postFields = new List<KeyValuePair<string, string>>()
{new KeyValuePair<string, string>(JsonDataFieldName, json)};
RedirectPost(url, postFields);
}
protected T GetPostData<T>() where T: class
{
var urlEncodedFieldData = Request.Params[JsonDataFieldName];
if (string.IsNullOrEmpty(urlEncodedFieldData))
{
return null;// default(T);
}
var fieldData = HttpUtility.UrlDecode(urlEncodedFieldData);
var result = JsonConvert.DeserializeObject<T>(fieldData);
return result;
}

Resources