简体   繁体   English

如何在 asp.net core 中修改 HttpContext.Request.Form

[英]How to modify HttpContext.Request.Form in asp.net core

I have an HttpContext.Request object that has data in the Form that is wrong and I want to fix it up and send the correct HttpContext on its way.我有一个 HttpContext.Request 对象,它的表单中的数据是错误的,我想修复它并在途中发送正确的 HttpContext。 HttpContext.Request.Form is readonly, but if it wasn't I would have simply done the following; HttpContext.Request.Form 是只读的,但如果不是,我会简单地执行以下操作; HttpContext.Request.Form["a"] = "the correct value for a"; HttpContext.Request.Form["a"] = "a 的正确值";

So, where is the best place in the pipeline to do this.那么,在管道中执行此操作的最佳位置在哪里。 Is it possible to make the HttpContext.Request.Form write accessable via reflection?是否可以通过反射使 HttpContext.Request.Form 可写访问?

This was easier than I thought.这比我想象的要容易。 I am doing this in my middleware which is there to correct bad form data that came in.我在我的中间件中执行此操作,以纠正传入的错误表单数据。

public async Task Invoke(HttpContext context)
{
    ....
    NameValueCollection fcnvc = context.Request.Form.AsNameValueCollection();
    fcnvc.Set("a", "the correct value of a");
    fcnvc.Set("b", "a value the client forgot to post");
    Dictionary<string, StringValues> dictValues = new Dictionary<string, StringValues>();
    foreach (var key in fcnvc.AllKeys)
    {
      dictValues.Add(key, fcnvc.Get(key));
    }
    var fc = new FormCollection(dictValues);
    context.Request.Form = fc;
    ....
    await _next.Invoke(context);
}

Interestingly the FormCollection is readonly, but the HttpContext.Request object is not thus allowing me to replace the entire Form.有趣的是,FormCollection 是只读的,但 HttpContext.Request 对象不允许我替换整个表单。

AsNameValueCollection is inside of IdentityServer4.dll. AsNameValueCollection 在 IdentityServer4.dll 中。

public static class IReadableStringCollectionExtensions
{
    [DebuggerStepThrough]
    public static NameValueCollection AsNameValueCollection(this IDictionary<string, StringValues> collection)
    {
        NameValueCollection values = new NameValueCollection();
        foreach (KeyValuePair<string, StringValues> pair in collection)
        {
            string introduced3 = pair.get_Key();
            values.Add(introduced3, Enumerable.First<string>(pair.get_Value()));
        }
        return values;
    }

    [DebuggerStepThrough]
    public static NameValueCollection AsNameValueCollection(this IEnumerable<KeyValuePair<string, StringValues>> collection)
    {
        NameValueCollection values = new NameValueCollection();
        foreach (KeyValuePair<string, StringValues> pair in collection)
        {
            string introduced3 = pair.get_Key();
            values.Add(introduced3, Enumerable.First<string>(pair.get_Value()));
        }
        return values;
    }
}

A bit complex but shorter solution有点复杂但更短的解决方案

var collection = HttpContext.Request.Form;
var propInfo = collection.GetType().GetProperty("IsReadOnly", BindingFlags.Instance | BindingFlags.NonPublic);
propInfo.SetValue(collection, false, new object[]{});
collection.Remove("a");
collection.Add("a", "the correct value for a");

System.Diagnostics.Debug.Write(HttpContext.Request["a"]); // the correct value for a

Enjoy!享受!

Here's a .NET Core/5 solution that worked for me without using the Identity Server package.这是一个 .NET Core/5 解决方案,它在不使用 Identity Server 包的情况下对我有用。

Basically you build a new dictionary of type <string, StringValues> out of the existing form collection, modify the values in the dictionary how you want, then create a new FormCollection from that dictionary and set it to context.Request.Form .基本上,您从现有的表单集合中构建一个<string, StringValues>类型的新字典,根据需要修改字典中的值,然后从该字典创建一个新的FormCollection并将其设置为context.Request.Form The important thing to remember is that the value which is of type StringValues is just an array of strings!要记住的重要一点是,StringValues 类型的值只是一个字符串数组!

This example demonstrates me removing a "client_id" field from the request form.此示例演示了我从请求表单中删除“client_id”字段。

var formDictionary = new Dictionary<string, StringValues>();
var form = context.Request.Form;

foreach (var key in form.Keys)
{
    // Only add if key is NOT client_id
    if (key != "client_id")
    {
        form.TryGetValue(key, out StringValues formValues);

        formDictionary.Add(key, formValues);
    }
}

FormCollection formCollection = new FormCollection(formDictionary);

context.Request.Form = formCollection;

Here is another example of me changing the "client_id" field to "NewValue"这是我将“client_id”字段更改为“NewValue”的另一个示例

var formDictionary = new Dictionary<string, StringValues>();
var form = context.Request.Form;

foreach (var key in form.Keys)
{
    form.TryGetValue(key, out StringValues formValues);

    // Change client_id value to "NewValue"
    if (key == "client_id")
    {
        formValues = new string[] { "NewValue" };
    }

    formDictionary.Add(key, formValues);
}

FormCollection formCollection = new FormCollection(formDictionary);

context.Request.Form = formCollection;

I personally prefer to use an extended method to do this.我个人更喜欢使用扩展方法来做到这一点。

public static IFormCollection PushToForm(this IFormCollection form, Dictionary<string, StringValues> data)
{
    var formDictionary = new Dictionary<string, StringValues>();
    foreach (var k in form.Keys)
    {
        form.TryGetValue(k, out StringValues v);
        formDictionary.Add(k, v);
    }

    foreach (var x in data) formDictionary.Add(x.Key, x.Value);
    return new FormCollection(formDictionary);
}

Example:例子:

Request.Form = Request.Form.PushToForm(new Dictionary<string, StringValues>()
{
    { "key1", new string[] { "value1" } },
    { "key2", new string[] { "value2" } },
    { "key3", new string[] { "value3" } },
    ...
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM