This seems like a simple operation.
We have a need in our development environment (running on XP/IIS 5) to add some headers into each HttpRequest arriving at our application. (This is to simulate a production environment that we don't have available in dev). At first blush, this seemed like a simple HttpModule, along the lines of:
public class Dev_Sim: IHttpModule
{
public void Init(HttpApplication app)
{
app.BeginRequest += delegate { app.Context.Request.Headers.Add("UserName", "XYZZY"); };
}
public void Dispose(){}
}
But on trying to do that, I find that the Headers collection of the Request is read-only, and the Add method fails with an OperationNotSupported exception.
Spending a couple hours researching this on Google, I've come up with no easy answer to what should be a relatively straight-forward problem.
Does anyone have any pointers?
Okay, with the assistance of a co-worker and some experimentation, I found that this can be done with the assistance of some protected properties and methods accessed through reflection:
var headers = app.Context.Request.Headers;
Type hdr = headers.GetType();
PropertyInfo ro = hdr.GetProperty("IsReadOnly",
BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.IgnoreCase | BindingFlags.FlattenHierarchy);
// Remove the ReadOnly property
ro.SetValue(headers, false, null);
// Invoke the protected InvalidateCachedArrays method
hdr.InvokeMember("InvalidateCachedArrays",
BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance,
null, headers, null);
// Now invoke the protected "BaseAdd" method of the base class to add the
// headers you need. The header content needs to be an ArrayList or the
// the web application will choke on it.
hdr.InvokeMember("BaseAdd",
BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance,
null, headers,
new object[] { "CustomHeaderKey", new ArrayList {"CustomHeaderContent"}} );
// repeat BaseAdd invocation for any other headers to be added
// Then set the collection back to ReadOnly
ro.SetValue(headers, true, null);
This works for me, at least.
You can add to the Header this way. This is a way to add credential information to the request before it enter the authentication sequence.
string cred = "UN:PW";
System.Web.HttpContext.Current.Request.Headers.Add("Authorization", "Basic " +Convert.ToBase64String(Encoding.ASCII.GetBytes(cred)));
Related
Disclaimer: I'm doing this for learning purposes. This is not going to be used in code.
I'm trying to understand how method table are structure for generics, I want to dynamically appending to methods at runtime. I found a very useful stack overflow question reference for getting me started.
I have a simple controller which I'm using as a test to verify my methods are swapping:
public class ValuesController : ControllerBase
{
static ValuesController() {
var methodToReplace = typeof(ValuesController).GetMethod(nameof(ValuesController.Seven),
BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
var methodToAppend = typeof(ValuesController).GetMethod(nameof(ValuesController.Eight),
BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
new Initializer(methodToReplace, methodToAppend);
}
[HttpGet("Seven")]
public int Seven(string id)
{
return 7;
}
[HttpGet("Eight")]
public int Eight(string id)
{
return 8;
}
}
I have a class Initializer which is in charge of handling appending to the method.
public class Initializer
{
public Initializer(MethodInfo methodToReplace, MethodInfo methodToAppend)
{
var dummyMethod = typeof(Initializer).GetMethod(nameof(Dummy),
BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
var proxyMethod = typeof(Initializer).GetMethod(nameof(Proxy),
BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
var appendedMethod = typeof(Initializer).GetMethod(nameof(Appended),
BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
dummyMethod.OneWayReplace(methodToReplace);
methodToReplace.OneWayReplace(proxyMethod);
appendedMethod.OneWayReplace(methodToAppend);
}
public int Proxy(string id)
{
Dummy(id);
return Appended(id);
}
public int Dummy(string id)
{
return 0;
}
public int Appended(string id)
{
return 0;
}
}
And then I have the Extensions which I've obtained from the original stackoverflow question:
public static class InjectionExtensions
{
// Note: This method replaces methodToReplace with methodToInject
// Note: methodToInject will still remain pointing to the same location
public static unsafe MethodReplacementState OneWayReplace(this MethodInfo methodToReplace, MethodInfo methodToInject)
{
//#if DEBUG
RuntimeHelpers.PrepareMethod(methodToReplace.MethodHandle);
RuntimeHelpers.PrepareMethod(methodToInject.MethodHandle);
//#endif
MethodReplacementState state;
IntPtr tar = methodToReplace.MethodHandle.Value;
var inj = methodToInject.MethodHandle.Value + 8;
if (!methodToReplace.IsVirtual)
tar += 8;
else
{
var index = (int)(((*(long*)tar) >> 32) & 0xFF);
var classStart = *(IntPtr*)(methodToReplace.DeclaringType.TypeHandle.Value + (IntPtr.Size == 4 ? 40 : 64));
tar = classStart + IntPtr.Size * index;
}
#if DEBUG
tar = *(IntPtr*)tar + 1;
inj = *(IntPtr*)inj + 1;
state.Location = tar;
state.OriginalValue = new IntPtr(*(int*)tar);
*(int*)tar = *(int*)inj + (int)(long)inj - (int)(long)tar;
return state;
#else
state.Location = tar;
state.OriginalValue = *(IntPtr*)tar;
* (IntPtr*)tar = *(IntPtr*)inj;
return state;
#endif
}
}
Note: Using the current setup everything works fine. However, the second I change the Initializer class to be a generic class Initializer<T> I get a memory violation:
System.AccessViolationException: 'Attempted to read or write protected memory. This is often an indication that other memory is corrupt.'
My guess is that either the methodToReplace.DeclaringType.TypeHandle.Value calculation differs for generics, Or since the compiler is the one who generates the generic class it written to protected memory?
Edit
I've found more information I need to prepare the method properly when using generic parameters e.g:
RuntimeHelpers.PrepareMethod(methodToInject.MethodHandle, new[] { typeof(T).TypeHandle });
However there are still a few more pieces to the puzzle to get this working.
Edit
There are a few open source project's such as harmony that do similar things, However it looks like their emitting their own assemblies. While I've considered the option, I would still prefer to understand how I method tables work with generics
How can I append to methods that reside in generic classes?
I suppose you have already seen: Dynamically replace the contents of a C# method?
I have adapted some of those methods in my own project # https://github.com/juliusfriedman/net7mma_core/blob/master/Concepts/Classes/MethodHelper.cs
I think the problem is that if your are running with the Debugger Attached then you need to also handle the portion of the logic which is currently defined by IFDEF at compilation time and replace that with an System.Diagnostics.Debugger.IsAttached although the offsets calculations (to jump over the debugger injected code) will probably have to change depending on various things like the version of the framework in use.
See https://github.com/juliusfriedman/net7mma_core/blob/master/Concepts/Classes/MethodHelper.cs#L35
This works for me in .Net Core 3.1 when the debugger IS NOT attached and I am running in Release mode, when running in Debug mode with or without the debugger attached or in Release mode with the debugger attached I receive different exceptions. (In debug I receive Arithmetic Overflow, while in release I receive Execution Engine Exception).
Furthermore this only works until the JIT Tiering kicks in, if I run the method a 2nd time without the debugger attached I am getting a Internal CLR Error.
I believe this has to do with the code injected by the debugger when attached and to be honest I am not up to do date on exactly what the debugger is injecting when attached.
I would make a simplified repo of the problem and ask a question # https://github.com/dotnet/runtime if you need this to work with the debugger attached and I am sure someone there will guide you in the right direction.
Anti-virus scans the .Net deployed folders. Because of this, application gets logged out frequently for the customers.
Requires lot of approval in order to get exemption at the folder level for the project. So, I used below code:
//FIX disable AppDomain restart when deleting subdirectory
//This code will turn off monitoring from the root website directory.
//Monitoring of Bin, App_Themes and other folders will still be operational, so updated DLLs will still auto deploy.
System.Reflection.PropertyInfo p = typeof(System.Web.HttpRuntime).GetProperty("FileChangesMonitor", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static);
object o = p.GetValue(null, null);
System.Reflection.FieldInfo f = o.GetType().GetField("_dirMonSubdirs", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.IgnoreCase);
object monitor = f.GetValue(o);
System.Reflection.MethodInfo m = monitor.GetType().GetMethod("StopMonitoring", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic); m.Invoke(monitor, new object[] { });
Used this article for above code.
Code works fine for a day. But, problem starts again next day. So, I replace the deployed folder again. Then, everything works fine.
Would like to know what causes the problem starts again. What should be done to not face again.
Also, how to stop scanning all the folders where application deployed. Because, application has custom folders where output files will be saved. This also should not be scanned.
Thanks in advance!
This is because you have your app pool being recycled by IIS (which is a good thing, because it will prevent any memory leaks you might have).
When this happens, Application_start is no longer called: https://msdn.microsoft.com/en-us/library/ms178473.aspx (same applies for IIS 7.0+)
What you should do is set up a static field in your Global.asax and on each Application_AcquireRequestState check if it is set to true. if not, run the code you posted, and then set the field to true.
This will ensure that the code will only ever run once per your worker process being alive.
private static bool hasRemovedFoldersFromMonitoring = false;
protected void Application_AcquireRequestState(object sender, EventArgs e)
{
if(!hasRemovedFoldersFromMonitoring){
System.Reflection.PropertyInfo p = typeof(System.Web.HttpRuntime).GetProperty("FileChangesMonitor", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static);
object o = p.GetValue(null, null);
System.Reflection.FieldInfo f = o.GetType().GetField("_dirMonSubdirs", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.IgnoreCase);
object monitor = f.GetValue(o);
System.Reflection.MethodInfo m = monitor.GetType().GetMethod("StopMonitoring", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic); m.Invoke(monitor, new object[] { });
hasRemovedFoldersFromMonitoring = true;
}
}
Since there are only 2 monitors inside the FileChangesMonitor class, you simply need to stop monitoring on both, so the full listing would be:
// Add at the top of the file
using System.Reflection;
// anywhere
private static bool hasRemovedFoldersFromMonitoring = false;
private void StopMonitoring(FileChangesMonitor fcm, string monitorName)
{
var f = typeof(FileChangesMonitor).GetField(monitorName, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.IgnoreCase);
var monitor = f.GetValue(fcm);
var m = monitor.GetType().GetMethod("StopMonitoring", BindingFlags.Instance |BindingFlags.NonPublic);
m.Invoke(monitor, new object[] { });
}
protected void Application_AcquireRequestState(object sender, EventArgs e)
{
if(!hasRemovedFoldersFromMonitoring){
var fcmPi = typeof(System.Web.HttpRuntime).GetProperty("FileChangesMonitor", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);
var fcm = (FileChangesMonitor)fcmPi .GetValue(null, null);
this.StopMonitoring(fcm, "_dirMonSubdirs");
this.StopMonitoring(fcm, "_dirMonAppPathInternal");
hasRemovedFoldersFromMonitoring = true;
}
}
Thanks a lot to #zaitsman for his help
With his help, modified the code like below
<%# import namespace="System.Reflection"%>
private static bool hasRemovedFoldersFromMonitoring = false;
protected void Application_AcquireRequestState(object sender, EventArgs e)
{
if (!hasRemovedFoldersFromMonitoring)
{
PropertyInfo fcmPi = typeof(System.Web.HttpRuntime).GetProperty("FileChangesMonitor", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);
object o = fcmPi.GetValue(null, null);
FieldInfo fi_dirMonSubdirs = o.GetType().GetField("_dirMonSubdirs", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.IgnoreCase);
object monitor_dirMonSubdirs = fi_dirMonSubdirs.GetValue(o);
MethodInfo m_dirMonSubdirs = monitor_dirMonSubdirs.GetType().GetMethod("StopMonitoring", BindingFlags.Instance | BindingFlags.NonPublic);
m_dirMonSubdirs.Invoke(monitor_dirMonSubdirs, new object[] { });
FieldInfo fi_dirMonAppPathInternal = o.GetType().GetField("_dirMonAppPathInternal", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.IgnoreCase);
object monitor_dirMonAppPathInternal = fi_dirMonAppPathInternal.GetValue(o);
if (monitor_dirMonAppPathInternal != null)
{
MethodInfo m_dirMonAppPathInternal = monitor_dirMonAppPathInternal.GetType().GetMethod("StopMonitoring", BindingFlags.Instance | BindingFlags.NonPublic);
m_dirMonAppPathInternal.Invoke(monitor_dirMonAppPathInternal, new object[] { });
}
hasRemovedFoldersFromMonitoring = true;
}
}
Hope code would help someone
However, I initially received null error when accessing monitor_dirMonAppPathInternal object. If anyone could say when the object will not be null, it would be helpful
I've been using Selenium for writing an end to end tests using the .net framework 4.6.
For a new project I'm using Selenium to do some web crawling but I'm experiencing enormous lag on very simple Selenium tasks.
Please look at the screenshot below:
The code itself is here:
public IList<Category> ListAllParentCategories()
{
var categories = new List<Category>();
var liItems = _driver.FindElements(By.CssSelector(".nav__branch.branch ul.tree li"));
foreach(var liItem in liItems)
{
var innerLink = liItem.FindElement(By.TagName("a"));
var c = new Category();
c.Id = long.Parse(liItem.GetAttribute("id"));
c.Link = innerLink.GetAttribute("href");
c.Name = innerLink.Text;
c.Parent = null;
categories.Add(c);
}
return categories;
}
From my experience, this should not take minutes to complete. Basically, we're just looking for a list of LI elements and then we query for some more info related to that element, which does not require interaction from the browser as it's already contained in the WebElement.
Yet this procedure (for 22 categories) takes at least an entire minute. Fetching the innerlink.GetAttribute("id") takes an entire second.
Now while trying to figure out why this is happening, I've been removing all thread related stuff and right now this code runs from a Console app. There's no improvement at all.
A curious thing is that when I open the innerLink in the debugger, I can see that most properties are using another thread?! I assume this is what is causing the long delays?
My setup is as follows:
- Console app running .NET Core 2.0
Dependencies:
- Selenium.Chrome.WebDriver 2.32.00
- Selenium.WebDriver 3.6.0
Update: This problem is definitely related to the .NET core variant of Selenium Webdriver. After converting the project to a regular .NET Framework 4.6 Console app, everything is 10 times faster.
There is a dirty fix for the problem for now.
//this is in my Dependency Register method
string driverPath = $#"{AppDomain.CurrentDomain.BaseDirectory}";
var service = FirefoxDriverService.CreateDefaultService(driverPath);
container.RegisterInstance<IWebDriver>(new FirefoxDriver(service), new PerThreadLifetimeManager());
FixDriverCommandExecutionDelay(container.Resolve<IWebDriver>());
and the method looks something like this:
//to be deleted when https://github.com/dotnet/corefx/issues/24104 is fixed
//in .net core 2.0
public static void FixDriverCommandExecutionDelay(IWebDriver driver)
{
PropertyInfo commandExecutorProperty = typeof(RemoteWebDriver).GetProperty("CommandExecutor", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetProperty);
ICommandExecutor commandExecutor = (ICommandExecutor)commandExecutorProperty.GetValue(driver);
FieldInfo remoteServerUriField = commandExecutor.GetType().GetField("remoteServerUri", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.SetField);
if (remoteServerUriField == null)
{
FieldInfo internalExecutorField = commandExecutor.GetType().GetField("internalExecutor", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.GetField);
commandExecutor = (ICommandExecutor)internalExecutorField.GetValue(commandExecutor);
remoteServerUriField = commandExecutor.GetType().GetField("remoteServerUri", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.SetField);
}
if (remoteServerUriField != null)
{
string remoteServerUri = remoteServerUriField.GetValue(commandExecutor).ToString();
string localhostUriPrefix = "http://localhost";
if (remoteServerUri.StartsWith(localhostUriPrefix))
{
remoteServerUri = remoteServerUri.Replace(localhostUriPrefix, "http://127.0.0.1");
remoteServerUriField.SetValue(commandExecutor, new Uri(remoteServerUri));
}
}
the answer to the problem is explained fully in this thread: https://github.com/dotnet/corefx/issues/24104
Answer taken from there also, credits given to the good folks!
It works for me on FF driver v0.19.1, Selenium v3.8
I want to switch this panel on/off by C# script while playing.
Is this possible? Haven't found any Editor API functions for this.
You can do it with reflection. Modified similar answer I made long ago. Below is a working set/get stats function. Tested with Unity 5.4.0f1. I put the Unity version so that people won't complain when it stops working. Unity's update can break this anytime if they rename any of the variables.
GameView = A class that is used to represent Unity GameView tab in
the Editor.
GetMainGameView = static function that returns current GameView
instance.
m_Stats = a boolean variable that is used to determine if stats
should be displayed or not.
Code:
//Show/Hide stats
void showStats(bool enableStats)
{
Assembly asm = Assembly.GetAssembly(typeof(Editor));
Type type = asm.GetType("UnityEditor.GameView");
if (type != null)
{
MethodInfo gameViewFunction = type.GetMethod("GetMainGameView", BindingFlags.Static |
BindingFlags.NonPublic);
object gameViewInstance = gameViewFunction.Invoke(null, null);
FieldInfo getFieldInfo = type.GetField("m_Stats", BindingFlags.Instance |
BindingFlags.NonPublic | BindingFlags.Public);
getFieldInfo.SetValue(gameViewInstance, enableStats);
}
}
//Returns true if stats is enabled
bool statsIsEnabled()
{
Assembly asm = Assembly.GetAssembly(typeof(Editor));
Type type = asm.GetType("UnityEditor.GameView");
if (type != null)
{
MethodInfo gameViewFunction = type.GetMethod("GetMainGameView", BindingFlags.Static |
BindingFlags.NonPublic);
object gameViewInstance = gameViewFunction.Invoke(null, null);
FieldInfo getFieldInfo = type.GetField("m_Stats", BindingFlags.Instance |
BindingFlags.NonPublic | BindingFlags.Public);
return (bool)getFieldInfo.GetValue(gameViewInstance);
}
return false;
}
Usage:
//Show stats
showStats(true);
//Hide stats
showStats(false);
//Read stats
bool stats = statsIsEnabled();
No it's not possible, unless you are a persistent hacker. GameView is an internal class, not accessible for editor scripting. But hey, there always is an option for good ol' reflection. This question will set you on the right track:
http://answers.unity3d.com/questions/179775/game-window-size-from-editor-window-in-editor-mode.html
https://msdn.microsoft.com/en-us/library/system.uri(v=vs.110).aspx
According to the reference above, when specifying an ftp url, the uri class should not compact the url. For example, the following ftp url:
Uri uri = new Uri("ftp://myUrl/%2E%2E/%2E%2E");
Console.WriteLine(uri.AbsoluteUri);
Console.WriteLine(uri.PathAndQuery);
should result in:
AbsoluteUri: "ftp://myUrl/%2E%2E/%2E%2E"
PathAndQuery: "/%2E%2E/%2E%2E"
But, this is NOT what I'm seeing. When I execute the above code using .NET framework 4.5.1, I see:
AbsoluteUri: "ftp://myUrl/"
PathAndQuery: "/"
Moreover, adding to my app.config seems to have no effect:
<uri>
<schemeSettings>
<add name="ftp" genericUriParserOptions="DontUnescapePathDotsAndSlashes" />
</schemeSettings>
</uri>
Since several people have been able to recreate the issue, I've created a bug report with Microsoft. Feel free to upvote:
https://connect.microsoft.com/VisualStudio/feedback/details/2046491/uri-canonicalization-compacting-ftp-scheme
Created a bug report with Microsoft:
https://connect.microsoft.com/VisualStudio/Feedback/Details/2046491
At present, I am working around this issue by (hacking via reflection) removing two flags from the UriParser object within the Uri class:
I call the method below once when my application is instantiating. After instantiation, every FTP Uri object will utilize the new flag combination when parsing.
// CompressPath = 0x800000, // For an authority based Uri remove/compress /./ /../ in the path
// UnEscapeDotsAndSlashes = 0x2000000, // additionally unescape dots and slashes before doing path compression
/// <summary>
/// http://referencesource.microsoft.com/#System/net/System/_UriSyntax.cs
/// </summary>
public static void LeaveDotsAndSlashesEscaped() {
Uri uri = new Uri("ftp://myUrl/%2E%2E/%2E%2E/");
if (uri == null) {
throw new ArgumentNullException("uri");
}
FieldInfo fieldInfo = uri.GetType().GetField("m_Syntax", BindingFlags.Instance | BindingFlags.NonPublic);
if (fieldInfo == null) {
throw new MissingFieldException("'m_Syntax' field not found");
}
object uriParser = fieldInfo.GetValue(uri);
fieldInfo = typeof(UriParser).GetField("m_Flags", BindingFlags.Instance | BindingFlags.NonPublic);
if (fieldInfo == null) {
throw new MissingFieldException("'m_Flags' field not found");
}
object uriSyntaxFlags = fieldInfo.GetValue(uriParser);
// Clear the flags that we don't want
uriSyntaxFlags = (int)uriSyntaxFlags & ~0x2000000 & ~0x800000;
fieldInfo.SetValue(uriParser, uriSyntaxFlags);
}