Convert HttpCookieCollection to NameValueCollection - c#

My objective is to store all request(*QueryString,Form,Headers,Cookies*) information to a single NameValueCollection.
Here is my code so far
var mainNVC = new NameValueCollection();
mainNVC.Add(context.Request.Form); //works
mainNVC.Add(context.Request.Headers); //works
mainNVC.Add(context.Request.QueryString); //works
mainNVC.Add(context.Request.Cookies); // error: Argument 1: cannot convert from 'System.Web.HttpCookieCollection' to 'System.Collections.Specialized.NameValueCollection'
Tried using Request.Param however, I don't want the server variables to be included.

This doesn't work because Request.Cookies is of type HttpCookieCollection.
You'll need to convert it to a NameValueCollection.
You can create an extension method called ToNameValueCollection():
public static class CookieCollectionExtensions
{
public static NameValueCollection ToNameValueCollection(
this HttpCookieCollection cookieCollection)
{
var nvc = new NameValueCollection();
foreach (var key in cookieCollection.AllKeys)
{
nvc.Add(key, cookieCollection[key].Value);
}
return nvc;
}
}
And then when you add the Cookies:
mainNVC.Add(context.Request.Cookies.ToNameValueCollection());

Related

Activator.CreateInstance - MissingMethodException: Constructor on type 'xxx' not found

I have the following code
Driver Code
var provider = DataManager.BuildDatabase<FileDatabase>(config,false,dbPath).Result;
DataManager.cs
public static async Task<IStorageProvider> BuildDatabase<TStorageProvider>(DbConfig config,
bool isBuildUniqueAddress = false,params object[] buildParam) where TStorageProvider : IStorageProvider
{
var t = typeof(TStorageProvider);
//merging params
var buildConfig= new DbData(config);
buildParam= buildParam.ToList().Prepend(buildConfig).ToArray();
Console.WriteLine($"Building Database of type:{t.FullName}");
IStorageProvider? storageProvider = (IStorageProvider?)Activator.CreateInstance(t,buildParam);
}
and Here is my Constructor for type FileDatabase
FileDatabase.cs
public FileDatabase(DbConfig config,string dbPath)
{
_dbData = new DbData(config);
DbPath=dbPath;
if (!File.Exists(dbPath))
{
Flush().RunSynchronously();
}
}
When I try to execute code above, it gives me:
MissingMethodException: Constructor on type 'assertUpdaterRefactor.StorageProvider.FileDatabase' not found.\
I tried to debug content of variable buildParam
.
The debugger shows the buildParam is an object array and exactly matches the constructor. I just can't figure out the reason causing this problem. Please help
UPDATE:
When I tried to create a new object array. The issue fixed magically
IStorageProvider? storageProvider = (IStorageProvider?)Activator.CreateInstance(t, new object[]{config,"someStringValue"});
Here is the original code copied from above just for reference
IStorageProvider? storageProvider = (IStorageProvider?)Activator.CreateInstance(t,buildParam);
I want to know the causes and why the original code does not work.
The first argument of the FileDatabase is DbConfig, in your BuildDatabase you use a type DbData.
So instead of passing an instance of var buildConfig= new DbData(config); pass the config directly.
Would be something like:
public static async Task<IStorageProvider> BuildDatabase<TStorageProvider>(DbConfig config,
bool isBuildUniqueAddress = false,params object[] buildParam) where TStorageProvider : IStorageProvider
{
var t = typeof(TStorageProvider);
//merging params
buildParam= buildParam.ToList().Prepend(config).ToArray();
Console.WriteLine($"Building Database of type:{t.FullName}");
IStorageProvider? storageProvider = (IStorageProvider?)Activator.CreateInstance(t,buildParam);
}

C# invoke function in foreach loop [duplicate]

Hi I am trying to use C# reflection to call a method that is passed a parameter and in return passes back a result. How can I do that? I've tried a couple of things but with no success. I'm used to PHP and Python where this can be done on a single line so this is very confusing to me.
In essence this is how the call would be made without reflection:
response = service.CreateAmbience(request);
request has these objects:
request.UserId = (long)Constants.defaultAmbience["UserId"];
request.Ambience.CountryId = (long[])Constants.defaultAmbience["CountryId"];
request.Ambience.Name.DefaultText = (string)Constants.defaultAmbience["NameDefaultText"];
request.Ambience.Name.LanguageText = GetCultureTextLanguageText((string)Constants.defaultAmbience["NameCulture"], (string)Constants.defaultAmbience["NameText"]);
request.Ambience.Description.DefaultText = (string)Constants.defaultAmbience["DescriptionText"];
request.Ambience.Description.LanguageText = GetCultureTextLanguageText((string)Constants.defaultAmbience["DescriptionCulture"], (string)Constants.defaultAmbience["DescriptionDefaultText"]);
This is my function to implement the reflection where serviceAction for the case above would be "CreateAmbience":
public static R ResponseHelper<T,R>(T request, String serviceAction)
{
ICMSCoreContentService service = new ContentServiceRef.CMSCoreContentServiceClient();
R response = default(R);
response = ???
}
Something along the lines of:
MethodInfo method = service.GetType().GetMethod(serviceAction);
object result = method.Invoke(service, new object[] { request });
return (R) result;
You may well want to add checks at each level though, to make sure the method in question is actually valid, that it has the right parameter types, and that it's got the right return type. This should be enough to get you started though.
Here's a quick example of calling an object method by name using reflection:
Type thisType = <your object>.GetType();
MethodInfo theMethod = thisType.GetMethod(<The Method Name>);
theMethod.Invoke(this, <an object [] of parameters or null>);
If you're on .NET 4, use dynamic:
dynamic dService = service;
var response = dService.CreateAmbience(request);
You can use Delegate.CreateDelegate to obtain a delegate to the method by name:
public static R ResponseHelper<T,R>(T request, string serviceAction)
{
var service = new ContentServiceRef.CMSCoreContentServiceClient();
var func = (Func<T,R>)Delegate.CreateDelegate(typeof(Func<T,R>),
service,
serviceAction);
return func(request);
}

Converting large httpresponse stream to a JSON string?

Question Background:
Update:
I'm still not sure how to go about extracting the relevant information from this response. I have tried setting my response type to JSON but still receive the response as shown below. I have taken into account what has been said in regards to using NameValueCollection but still cant see how this will help with such a large response. Ideally I'd like this mapped to an object structure of some kind, it dosen't necessarily have to be JSON.
Question:
I'm currently using the PayPal Api 'ExpressCheckout' method to allow users to pay for items on my test site. A HTTP response from the API provides a large response containing key information I need to extract - such as the buyers address, if the payment was succesful etc.
The Issue:
Currently I'm stuck on how to work with the response. Ideally I'd convert the data to a JSON string then use Newtonsoft to map the data to C# classes thus allowing easy access to the data. Here is an example of the Httpresponse:
TOKEN=EC%2XXXXXXXXXXXXXXXXXR&BILLINGAGREEMENTACCEPTEDSTATUS=0&CHECKOUTSTATUS=PaymentActionNotInitiated&TIMESTAMP=2015%2d01%2d02T21%3a11%3a30Z&CORRELATIONID=ab184fdba7a30&ACK=Success&VERSION=88%2e0&BUILD=14443165&EMAIL=test%40aol%2ecom&PAYERID=3XXXXXXXXXX4N&PAYERSTATUS=verified&BUSINESS=Test%20Biz%27s%20Test%20Store&FIRSTNAME=Joe&LASTNAME=King&COUNTRYCODE=GB&SHIPTONAME=Joe%20King%27s%20Test%20Store&SHIPTOSTREET=1%20Main%20Terrace&SHIPTOCITY=Wolverhampton&SHIPTOSTATE=West%20Midlands&SHIPTOZIP=W12%204LQ&SHIPTOCOUNTRYCODE=GB&SHIPTOCOUNTRYNAME=United%20Kingdom&ADDRESSSTATUS=Confirmed&CURRENCYCODE=GBP&AMT=15%2e56&ITEMAMT=15%2e56&SHIPPINGAMT=0%2e00&HANDLINGAMT=0%2e00&TAXAMT=0%2e00&INSURANCEAMT=0%2e00&SHIPDISCAMT=0%2e00&L_NAME0=ItemOne&L_QTY0=4&L_TAXAMT0=0%2e00&L_AMT0=3%2e89&L_ITEMWEIGHTVALUE0=%20%20%200%2e00000&L_ITEMLENGTHVALUE0=%20%20%200%2e00000&L_ITEMWIDTHVALUE0=%20%20%200%2e00000&L_ITEMHEIGHTVALUE0=%20%20%200%2e00000&PAYMENTREQUEST_0_CURRENCYCODE=GBP&PAYMENTREQUEST_0_AMT=15%2e56&PAYMENTREQUEST_0_ITEMAMT=15%2e56&PAYMENTREQUEST_0_SHIPPINGAMT=0%2e00&PAYMENTREQUEST_0_HANDLINGAMT=0%2e00&PAYMENTREQUEST_0_TAXAMT=0%2e00&PAYMENTREQUEST_0_INSURANCEAMT=0%2e00&PAYMENTREQUEST_0_SHIPDISCAMT=0%2e00&PAYMENTREQUEST_0_INSURANCEOPTIONOFFERED=false&PAYMENTREQUEST_0_SHIPTONAME=Joe%20King%27s%20Test%20Store&PAYMENTREQUEST_0_SHIPTOSTREET=1%20Main%20Terrace&PAYMENTREQUEST_0_SHIPTOCITY=Wolverhampton&PAYMENTREQUEST_0_SHIPTOSTATE=West%20Midlands&PAYMENTREQUEST_0_SHIPTOZIP=W12%204LQ&PAYMENTREQUEST_0_SHIPTOCOUNTRYCODE=GB&PAYMENTREQUEST_0_SHIPTOCOUNTRYNAME=United%20Kingdom&PAYMENTREQUEST_0_ADDRESSSTATUS=Confirmed&L_PAYMENTREQUEST_0_NAME0=ItemOne&L_PAYMENTREQUEST_0_QTY0=4&L_PAYMENTREQUEST_0_TAXAMT0=0%2e00&L_PAYMENTREQUEST_0_AMT0=3%2e89&L_PAYMENTREQUEST_0_ITEMWEIGHTVALUE0=%20%20%200%2e00000&L_PAYMENTREQUEST_0_ITEMLENGTHVALUE0=%20%20%200%2e00000&L_PAYMENTREQUEST_0_ITEMWIDTHVALUE0=%20%20%200%2e00000&L_PAYMENTREQUEST_0_ITEMHEIGHTVALUE0=%20%20%200%2e00000&PAYMENTREQUESTINFO_0_ERRORCODE=0
If anyone could give me an easy way to map this data to a C# object that would be great.
Is there any specific reason why you want it in JSON format? If its not requirement and if you can live with key value pair then here is one way you can process response as key value pair.
public partial class Form1 : Form
{
Dictionary<string, string> processedResponse = null;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
string rawResponse = "TOKEN=EC%2XXXXXXXXXXXXXXXXXR&BILLINGAGREEMENTACCEPTEDSTATUS=0&CHECKOUTSTATUS=PaymentActionNotInitiated&TIMESTAMP=2015%2d01%2d02T21%3a11%3a30Z&CORRELATIONID=ab184fdba7a30&ACK=Success&VERSION=88%2e0&BUILD=14443165&EMAIL=test%40aol%2ecom&PAYERID=3XXXXXXXXXX4N&PAYERSTATUS=verified&BUSINESS=Test%20Biz%27s%20Test%20Store&FIRSTNAME=Joe&LASTNAME=King&COUNTRYCODE=GB&SHIPTONAME=Joe%20King%27s%20Test%20Store&SHIPTOSTREET=1%20Main%20Terrace&SHIPTOCITY=Wolverhampton&SHIPTOSTATE=West%20Midlands&SHIPTOZIP=W12%204LQ&SHIPTOCOUNTRYCODE=GB&SHIPTOCOUNTRYNAME=United%20Kingdom&ADDRESSSTATUS=Confirmed&CURRENCYCODE=GBP&AMT=15%2e56&ITEMAMT=15%2e56&SHIPPINGAMT=0%2e00&HANDLINGAMT=0%2e00&TAXAMT=0%2e00&INSURANCEAMT=0%2e00&SHIPDISCAMT=0%2e00&L_NAME0=ItemOne&L_QTY0=4&L_TAXAMT0=0%2e00&L_AMT0=3%2e89&L_ITEMWEIGHTVALUE0=%20%20%200%2e00000&L_ITEMLENGTHVALUE0=%20%20%200%2e00000&L_ITEMWIDTHVALUE0=%20%20%200%2e00000&L_ITEMHEIGHTVALUE0=%20%20%200%2e00000&PAYMENTREQUEST_0_CURRENCYCODE=GBP&PAYMENTREQUEST_0_AMT=15%2e56&PAYMENTREQUEST_0_ITEMAMT=15%2e56&PAYMENTREQUEST_0_SHIPPINGAMT=0%2e00&PAYMENTREQUEST_0_HANDLINGAMT=0%2e00&PAYMENTREQUEST_0_TAXAMT=0%2e00&PAYMENTREQUEST_0_INSURANCEAMT=0%2e00&PAYMENTREQUEST_0_SHIPDISCAMT=0%2e00&PAYMENTREQUEST_0_INSURANCEOPTIONOFFERED=false&PAYMENTREQUEST_0_SHIPTONAME=Joe%20King%27s%20Test%20Store&PAYMENTREQUEST_0_SHIPTOSTREET=1%20Main%20Terrace&PAYMENTREQUEST_0_SHIPTOCITY=Wolverhampton&PAYMENTREQUEST_0_SHIPTOSTATE=West%20Midlands&PAYMENTREQUEST_0_SHIPTOZIP=W12%204LQ&PAYMENTREQUEST_0_SHIPTOCOUNTRYCODE=GB&PAYMENTREQUEST_0_SHIPTOCOUNTRYNAME=United%20Kingdom&PAYMENTREQUEST_0_ADDRESSSTATUS=Confirmed&L_PAYMENTREQUEST_0_NAME0=ItemOne&L_PAYMENTREQUEST_0_QTY0=4&L_PAYMENTREQUEST_0_TAXAMT0=0%2e00&L_PAYMENTREQUEST_0_AMT0=3%2e89&L_PAYMENTREQUEST_0_ITEMWEIGHTVALUE0=%20%20%200%2e00000&L_PAYMENTREQUEST_0_ITEMLENGTHVALUE0=%20%20%200%2e00000&L_PAYMENTREQUEST_0_ITEMWIDTHVALUE0=%20%20%200%2e00000&L_PAYMENTREQUEST_0_ITEMHEIGHTVALUE0=%20%20%200%2e00000&PAYMENTREQUESTINFO_0_ERRORCODE=0";
//Process response
processedResponse = ProcessResponse(rawResponse);
//Use received data e.g.
//Get First name
string fName = GetRecordValue("FIRSTNAME");
//Get Last name
string lName = GetRecordValue("LASTNAME");
}
private Dictionary<string,string> ProcessResponse(string response)
{
Dictionary<string, string> responseData = new Dictionary<string, string>();
if(!string.IsNullOrWhiteSpace(response))
{
string[] firstPass = response.Split(new char[] { '&' });
foreach(string pair in firstPass)
{
string[] secondPass = pair.Split(new char[] { '=' });
if(secondPass!=null && secondPass.Length>0)
{
responseData.Add(secondPass[0].Trim(), secondPass[1].Trim());
}
}
}
return responseData;
}
private string GetRecordValue(string record)
{
string recordValue = null;
if(processedResponse!=null)
{
if(!string.IsNullOrWhiteSpace(record) && processedResponse.ContainsKey(record))
{
recordValue= processedResponse[record];
}
}
return recordValue;
}
}
Still unsure what's the problem with dealing with it as a NameValueCollection.
E.g.
//NameValueCollection
//or use HttpUtility.ParseQueryString(some_string_of_names_values)
var foo = Request.QueryString;
var bar = foo["FIRSTNAME"]; //based on above this is "Joe"
Update:
It is response string which is being processed here and not request hence you wont be able to retrieve details using Request.QueryString
As stated in comments:
string rawResponse = "TOKEN=EC%2XXXXXXXXXXXXXXXXXR&BILLINGAGREEMENTACCEPTEDSTATUS=0&CHECKOUTSTATUS=PaymentActionNotInitiated&TIMESTAMP=2015%2d01%2d02T21%3a11%3a30Z&CORRELATIONID=ab184fdba7a30&ACK=Success&VERSION=88...."
var foo = HttpUtility.ParseQueryString(rawResponse); //NameValueCollection
var bar = foo["FIRSTNAME"]; //Joe

How to pass a dynamic pair of key/values to a function?

I've already read this an this, but this doesn't answer to my needs.
I'm learning Csharp and here's one of my first functions:
public void AskServer(string URL, WWWForm form)
{
WWWForm form = new WWWForm(URL);
form.AddField("step", StateManager.STEP_GET_CONF);
form.AddField("pseudo", this._pseudo);
form.AddField("jeton", this._dernierJeton.ToString());
/*... a bit more out of scope code...*/
}
I would like to do a (far more) generic stuff like this:
public void AskServer(string URL, ...)
{
WWWForm form = new WWWForm(URL);
/* do a loop on all parameters following the first one */
for (/*dont know how to write this*/) {
form.AddField(param[i], param[i+1]);
)
}
then call the function -somehow- like that:
AskServer("http://myweb", "pseudo", this._pseudo, "jeton", this._jeton);
Maybe if you have a nicer way of writing this, you are welcome, maybe something like in JavaScript:
AskServer("http://myweb", {
"pseudo": this._pseudo,
"jeton": this._jeton
});
One of my problems is that I need to pass value that may not be strings (key will always be).
The params keyword will let you specify a variable number of arguments (must be the last parameter). You can then treat that as an array.
public void AskServer(string url, params object[] args)
{
WWWForm form = new WWWForm(url);
for (int i = 0; i < args.GetLength(0); i++)
form.Addfield(args[i].ToString(), args[++i]);
}
Called as,
AskServer("http://myweb", "pseudo", 1, "jeton", 234);
Or as an alternative approach, use a list instead with strong type on the key (the generic declaration is ugly so you can alias it in namespaces)
using Kvp = System.Collections.Generic.KeyValuePair<string, object>;
....
public void AskServer(string url, List<Kvp> kvps)
{
WWWForm form = new WWWForm(url);
foreach (var arg in kvps)
form.Addfield(arg.Key, arg.Value);
}
Called as:
AskServer("http://myweb",
new List<Kvp>() {
new Kvp("pseudo", 1),
new Kvp("jeton", 234)
});
there are several ways to obtain this result.
parameter array, Tuple, anonymous types, ...
for example you can write
public void AskServer(string URL, params object[] values)
{
...
}
and pass as many parameters as you want
I would try this...
public void AskServer(string url, KeyValuePair<string, object>[] parameters)
{
WWWForm form = new WWWForm(URL);
/* do a loop on all parameters following the first one */
for (/*dont know how to write this*/) {
form.AddField(parameters[i].Key, parameters[i].Value);
)
}

populating a dictionary with links via HtmlAgility & custom webclient

private void button1_Click(object sender, EventArgs e)
{
test();
}
public void test()
{
Dictionary<string, string> LnksDict = new Dictionary<string, string>();
using (SmartWebClient smwc = new SmartWebClient())
{
HtmlAgilityPack.HtmlDocument htmlDoc = new HtmlAgilityPack.HtmlDocument();
htmlDoc.LoadHtml(smwc.DownloadString("http://www.google.com/adplanner/static/top1000/"));
var links = htmlDoc.DocumentNode
.Descendants("a").Select(x => x.Attributes["href"]);
foreach (var link in htmlDoc.DocumentNode.SelectNodes("//a"))
{
var UrlVal= link.Attributes["href"].Value;
var name = UrlVal.Split('.')[1];
LnksDict.Add(name, UrlVal);
}
}
}
#region <<=========== SmWbCl ============>>
public class SmartWebClient : WebClient
{
private readonly int maxConcurentConnectionCount;
public SmartWebClient(int maxConcurentConnectionCount = 20)
{
this.maxConcurentConnectionCount = maxConcurentConnectionCount;
}
protected override WebRequest GetWebRequest(Uri address)
{
var httpWebRequest = (HttpWebRequest)base.GetWebRequest(address);
if (httpWebRequest == null)
{
return null;
}
if (maxConcurentConnectionCount != 0)
{
this.Proxy = null;
this.Encoding = Encoding.GetEncoding("UTF-8");
httpWebRequest.ServicePoint.ConnectionLimit = maxConcurentConnectionCount;
}
return httpWebRequest;
}
}
#endregion
in this code i am trying to build a list of urls to be used as autoComplete source later.
what i am doing wrong is notc onditioning on adding the parsed values into the dictionary .
i need to find a way to add domain name as the key, even if already exist,
so i would like to be able to make a condition :
if the key in this dictionary already exists, add collection index of current link to string.value of key as a suffix
or if you would like to suggest a different solution all together... i will be happy to see new example.
thanks
I think what you want, rather than a Dictionary<string, string>, is a Dictionary<string, HashSet<string>>. That way, you can build a list of URLs for each domain. Your code to add an item to the list would be:
var UrlVal= link.Attributes["href"].Value;
var name = UrlVal.Split('.')[1];
// get links for this host
HashSet hostLinksList;
if (!LnksDict.TryGetValue(name, out hostLinksList))
{
hostLinksList = new HashSet<string>();
LnksDict.Add(name, hostLinksList);
}
// add the URL to the list of links for this host
hostLinksList.Add(UrlVal);
The key here is that calling Add on a HashSet when the item is already there won't throw an exception. It just doesn't add it again and returns false to indicate that the item was already in the collection.
When you're done, you have a list of URLs for each host (domain), which you can then use for your auto completion.
By the way, your method of splitting out the host using Split('.') isn't going to work very well. It assumes domains of the form "www.example.com". If you run into, for example, "example.com" (without the "www"), you're going to get "com" for the name. Also, "www.example.com" is going to collide with "www.example.org" and "www.example.co.uk". You need a better way of identifying hosts.

Categories

Resources