I was trying to modify a HTTP Header using C#. I tried to manipulate the Request.Headers on Page preinit event. But when i try to set anything to the Headers, i get PlatformNotSupportedException. Since We can not set a new NameValueCollection to Reqeust.Headers, I tried to set the value using following code:
Request.Headers.Set(HttpRequestHeader.UserAgent.ToString(), "some value");
Any idea how can this be achieved?
Try this:
HttpContext.Current.Request.Headers["User-Agent"] = "Some Value";
EDIT:
This could be your reason:
http://bigjimindc.blogspot.com/2007/07/ms-kb928365-aspnet-requestheadersadd.html
There is a code snippet in that, which adds a new header to the Request.Headers. Verified on Windows 7 32 bit OS too.
But you might want to replace the line:
HttpApplication objApp = (HttpApplication)r_objSender;
with:
HttpApplication objApp = (HttpApplication)HttpContext.Current.ApplicationInstance;
EDIT:
To replace the existing Header value, use:
t.InvokeMember("BaseSet", BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance, null, headers, new object[] { "Host", item });
where "Host" is a Header name.
Adding the complete (working) code from the linked blog - incase that blog vanishes
HttpApplication objApp = (HttpApplication)HttpContext.Current.ApplicationInstance;
HttpRequest Request = (HttpContext)objApp.Context.Request;
//get a reference
NameValueCollection headers = Request.Headers;
//get a type
Type t = headers.GetType();
System.Collections.ArrayList item = new System.Collections.ArrayList();
t.InvokeMember("MakeReadWrite",BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance,null,headers,null);
t.InvokeMember("InvalidateCachedArrays",BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance,null,headers,null);
item.Add("CUSTOM_HEADER_VALUE");
t.InvokeMember("BaseAdd",BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance,null,headers, new object[]{"CUSTOM_HEADER_NAME",item});
t.InvokeMember("MakeReadOnly",BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance,null,headers,null);
Related
I'm getting an error when i try to publish my JSON message with SSL(TLS) to kafka topic asynchronously.
var config = new Dictionary<string, string>
{
{ "bootstrap.servers", kafkurl},
{ "ssl.ca.location", certlocation},
{ "security.protocol", "SASL_SSL"},
{ "sasl.mechanism", "GSSAPI"},
{ "sasl.username", ""},
{ "sasl.password", ""}
};
using (var producer = new ProducerBuilder<Null, string>(config).Build())
{
var dr = producer.Produce(topicname, jsonmsg).Result;
Console.WriteLine($"Delivered '{dr.Value}' to: {dr.TopicPartitionOffset}");
}
Here "jsonmsg" is my actual data(JSON format) as string. How to convert this into Message as expected for this method..? Or Do you have any other method option to use here..? I expect to publish my JSON message along with SSL. Please help.
Try to add the magic line:
System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
I am migrating my API to .NET Core 2.2 and in my application is calling another wsdl (WCF) service. Upon calling that service, I'm getting an error saying
System.Net.Http.WinHttpException: The operation timed
Is there something wrong with the way i migrated? It is perfectly working in my previous solution running at .net 4.5
Here is the full inner text message.
InnerException: System.Net.Http.HttpRequestException: An error occurred while sending the request.
System.Net.Http.WinHttpException: The operation timed out
at System.Threading.Tasks.RendezvousAwaitable``1.GetResult()
at System.Net.Http.WinHttpHandler.StartRequest(WinHttpRequestState state)
--- End of inner exception stack trace --->
at System.ServiceModel.Channels.ServiceModelHttpMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at System.Net.Http.HttpClient.FinishSendAsyncUnbuffered(Task1 sendTask, HttpRequestMessage request, CancellationTokenSource cts, Boolean disposeCts)
at System.ServiceModel.Channels.HttpChannelFactory1.HttpClientRequestChannel.HttpClientChannelAsyncRequest.SendRequestAsync(Message message, TimeoutHelper timeoutHelper)
Does your soap request take longer than 30 seconds? If yes, you need to know that default timeout in .NET Core for soap request is 30 seconds.
It's a little tricky to change to timeout, but someone already figured it how:
static void Main(string[] args)
{
var client = new SimpleServiceClient();
client.OpenAsync().GetAwaiter().GetResult();
client.DelayedResponseAsync(2000).GetAwaiter().GetResult();
var channel = client.InnerChannel;
var httpChannelFactory = client.InnerChannel.GetProperty<IChannelFactory>();
var cacheField = httpChannelFactory.GetType().GetField("_httpClientCache", BindingFlags.NonPublic | BindingFlags.Instance);
var httpClientCache = cacheField.GetValue(httpChannelFactory);
var cacheDictionaryField = httpClientCache.GetType().GetField("_items", BindingFlags.NonPublic | BindingFlags.Instance);
IDictionary cacheDictionary = (IDictionary)cacheDictionaryField.GetValue(httpClientCache);
foreach(var cacheKey in cacheDictionary.Keys)
{
var cacheEntry = cacheDictionary[cacheKey];
var valueField = cacheEntry.GetType().GetField("value", BindingFlags.NonPublic | BindingFlags.Instance);
HttpClient httpClient = (HttpClient)valueField.GetValue(cacheEntry);
FixHttpClient(httpClient);
}
client.DelayedResponseAsync(50000).GetAwaiter().GetResult();
Console.WriteLine("Done");
Console.ReadLine();
}
private static void FixHttpClient(HttpClient httpClient)
{
var handlerField = typeof(HttpMessageInvoker).GetField("_handler", BindingFlags.NonPublic | BindingFlags.Instance);
DelegatingHandler delegatingHandler = (DelegatingHandler)handlerField.GetValue(httpClient); // Should be of type ServiceModelHttpMessageHandler
WinHttpHandler winHttpHandler = (WinHttpHandler)delegatingHandler.InnerHandler;
WinHttpHandler newHandler = new WinHttpHandler();
newHandler.ServerCredentials = winHttpHandler.ServerCredentials;
newHandler.CookieUsePolicy = winHttpHandler.CookieUsePolicy;
newHandler.ClientCertificates.AddRange(winHttpHandler.ClientCertificates);
newHandler.ServerCertificateValidationCallback = winHttpHandler.ServerCertificateValidationCallback;
newHandler.Proxy = winHttpHandler.Proxy;
newHandler.AutomaticDecompression = winHttpHandler.AutomaticDecompression;
newHandler.PreAuthenticate = winHttpHandler.PreAuthenticate;
newHandler.CookieContainer = winHttpHandler.CookieContainer;
// Fix the timeouts
newHandler.ReceiveHeadersTimeout = Timeout.InfiniteTimeSpan;
newHandler.ReceiveDataTimeout = Timeout.InfiniteTimeSpan;
newHandler.SendTimeout = Timeout.InfiniteTimeSpan;
var servicemodelHttpHandlerInnerHandlerField = delegatingHandler.GetType().GetField("_innerHandler", BindingFlags.NonPublic | BindingFlags.Instance);
servicemodelHttpHandlerInnerHandlerField.SetValue(delegatingHandler, newHandler);
var delegatingHandlerInnerHandlerField = typeof(DelegatingHandler).GetField("_innerHandler", BindingFlags.NonPublic | BindingFlags.Instance);
delegatingHandlerInnerHandlerField.SetValue(delegatingHandler, newHandler);
}
So eaily, pass your HttpClient to
Code directly copied from this gist.
I've a CMS application code which calls Response.Cache.SetNoStore() on all request and if i'm correct, this will be prevents proxies/cdn to cache those pages/content. Therefore, i'm conditionally calling the below code:
Response.Cache.SetCacheability(HttpCacheability.Public);
Response.Cache.SetMaxAge(new TimeSpan(0, 30, 0));
Response.Cache.SetValidUntilExpires(true);
But this doesn't take out the no-store param from the response header, this is the returned http header:
Cache-Control:public, no-store, must-revalidate, max-age=1800
Therefore my question is, how can i take out the nostore param pragmatically? If this isn't possible, how/where can i parse/modify the http-header, because i tried to parsed on PagePreRender event and the nostore param hasn't been applied...which leads to wonder at which life cycle is this appended to the header?
There is a way to undo SetNoStore once you call it. You need to use some creative routing to process the request in a different way or reflection to invoke the built-in reset that is private.
You can get access to HttpCachePolicyWrapper to access the underlying HttpCachePolicy, then assign the internal NoStore field or issue Reset to revert to the default cache policy.
response.Cache.SetNoStore(); // assign no-store
BindingFlags hiddenItems = BindingFlags.NonPublic | BindingFlags.Instance;
var httpCachePolicyWrapper = response.Cache.GetType(); // HttpCachePolicyWrapper type
var httpCache = httpCachePolicyWrapper.InvokeMember("_httpCachePolicy", BindingFlags.GetField | hiddenItems, null, response.Cache, null);
var httpCachePolicy = httpCache.GetType(); // HttpCachePolicy type
// Reset Cache Policy to Default
httpCachePolicy.InvokeMember("Reset", BindingFlags.InvokeMethod | hiddenItems, null, httpCache, null);
var resetAllCachePolicy = httpCachePolicy.InvokeMember("_noStore", BindingFlags.GetField | hiddenItems, null, httpCache, null);
response.Cache.SetNoStore(); // assign no-store
// Undo SetNoStore Cache Policy
httpCachePolicy.InvokeMember("_noStore", BindingFlags.SetField | hiddenItems, null, httpCache, new object[] { false });
var resetNoStoreOnly = httpCachePolicy.InvokeMember("_noStore", BindingFlags.GetField | hiddenItems, null, httpCache, null);
I'm having an unexpected behavior with the System.Uri class.
When an instance of System.Uri is created, and the UrlString has some patterns like ..., or ...#, or .#, the System.Uri removes all repeated . characters.
This is weird, but I believe this behavior is based on RFC 2396.
The problem begins when I try to download the HTML from this URL: http://www.submarino.com.br/produto/1/23853463/mundo+segundo+steve+jobs,+o:+as+frases+mais+inspiradoras+...
and the System.Uri removes all the repeated .s. As the web site doesn't recognize the "New URL," it redirects to the rriginal URL. Then a "System.Net.WebException: Too many automatic redirections were attempted" is thrown and the page is never reached.
How can I solve this issue?
You can use reflection to remove that particular attribute. Use this before your Uri call:
MethodInfo getSyntax = typeof(UriParser).GetMethod("GetSyntax", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
FieldInfo flagsField = typeof(UriParser).GetField("m_Flags", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
if (getSyntax != null && flagsField != null)
{
foreach (string scheme in new[] { "http", "https" })
{
UriParser parser = (UriParser)getSyntax.Invoke(null, new object[] { scheme });
if (parser != null)
{
int flagsValue = (int)flagsField.GetValue(parser);
// Clear the CanonicalizeAsFilePath attribute
if ((flagsValue & 0x1000000) != 0)
flagsField.SetValue(parser, flagsValue & ~0x1000000);
}
}
}
It has been reported to Connect before.
I need to programatically add an IIS 7.x site and I got stuck when this should be created with a HTTPS/SSL binding by default, usig SiteCollection.Add(string, string, string, byte[]) overload.
Giving https:*:80:test.localhost https:*:443:test.localhost as bindingInformation throws an ArgumentException with this message: The specified HTTPS binding is invalid.
What's wrong in this binding information?
Thank you.
EDIT: I'm using Microsoft.Web.Administration assembly.
Here is what I did to create https site and it worked. I skip some parts of code here, of course.
using Microsoft.Web.Administration
...
using(var manager = new ServerManager())
{
// variables are set in advance...
var site = manager.Sites.Add(siteName, siteFolder, siteConfig.Port);
var store = new X509Store(StoreName.AuthRoot, StoreLocation.LocalMachine);
store.Open(OpenFlags.OpenExistingOnly | OpenFlags.ReadWrite);
// certHash is my certificate's hash, byte[]
var binding = site.Bindings.Add("*:443:", certHash, store.Name);
binding.Protocol = "https";
store.Close();
site.ApplicationDefaults.EnabledProtocols = "http,https";
manager.CommitChanges();
}
UPD: the certificate is created from a pfx file the following way:
// get certificate from the file
string pfx = Directory.GetFiles(folder, "*.pfx", SearchOption.AllDirectories).FirstOrDefault();
var store = new X509Store(StoreName.Root, StoreLocation.LocalMachine);
store.Open(OpenFlags.OpenExistingOnly | OpenFlags.ReadWrite);
var certificate = new X509Certificate2(pfx, certPassword, X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet);
store.Add(certificate);
store.Close();
certHash = certificate.GetCertHash();
As far as I can see BindingInformation is without the protocol:
The value of this property is a colon-delimited string that includes
the IP address, port, and host name of the binding.
Source: http://msdn.microsoft.com/en-us/library/microsoft.web.administration.binding.bindinginformation%28v=vs.90%29.aspx
There is also a overload of that takes a parameter BindingProtocol:
public Site Add(
string name,
string bindingProtocol,
string bindingInformation,
string physicalPath
)
Source: http://msdn.microsoft.com/en-us/library/bb359364%28v=vs.90%29.aspx
Maybe you should use the Binding object offered by the Site instance as is offers more settings than the SiteCollection instance.