How to create a file to populate HttpContext.Current.Request.Files?

后端 未结 2 587
你的背包
你的背包 2021-01-13 07:08

In my Web API, The POST action method uploads a file on server.

For unit testing this method, I need to create a HttpContext and put a file inside its request:

2条回答
  •  误落风尘
    2021-01-13 07:19

    I was eventually able to add fake files to HttpContext for WebApi unit tests by making heavy use of reflection, given that most of the Request.Files infrastructure lies hidden away in sealed or internal classes.

    Once you've added the code below, files can be added relatively easily to HttpContext.Current:

    var request = new HttpRequest(null, "http://tempuri.org", null);
    AddFileToRequest(request, "File", "img/jpg", new byte[] {1,2,3,4,5});
    
    HttpContext.Current = new HttpContext(
        request,
        new HttpResponse(new StringWriter());
    

    With the heavy lifting done by:

    static void AddFileToRequest(
        HttpRequest request, string fileName, string contentType, byte[] bytes)
    {
        var fileSize = bytes.Length;
    
        // Because these are internal classes, we can't even reference their types here
        var uploadedContent = ReflectionHelpers.Construct(typeof (HttpPostedFile).Assembly,
            "System.Web.HttpRawUploadedContent", fileSize, fileSize);
        uploadedContent.InvokeMethod("AddBytes", bytes, 0, fileSize);
        uploadedContent.InvokeMethod("DoneAddingBytes");
    
        var inputStream = Construct(typeof (HttpPostedFile).Assembly,
            "System.Web.HttpInputStream", uploadedContent, 0, fileSize);
    
        var postedFile = Construct(fileName, 
                 contentType, inputStream);
        // Accessing request.Files creates an empty collection
        request.Files.InvokeMethod("AddFile", fileName, postedFile);
    }
    
    public static object Construct(Assembly assembly, string typeFqn, params object[] args)
    {
        var theType = assembly.GetType(typeFqn);
        return theType
          .GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, 
                 args.Select(a => a.GetType()).ToArray(), null)
          .Invoke(args);
    }
    
    public static T Construct(params object[] args) where T : class
    {
        return Activator.CreateInstance(
            typeof(T), 
            BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance,
            null, args, null) as T;
    }
    
    public static object InvokeMethod(this object o, string methodName, 
         params object[] args)
    {
        var mi = o.GetType().GetMethod(methodName, 
                 BindingFlags.NonPublic | BindingFlags.Instance);
        if (mi == null) throw new ArgumentOutOfRangeException("methodName",
            string.Format("Method {0} not found", methodName));
        return mi.Invoke(o, args);
    }
    

提交回复
热议问题