Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Instantiating an IFormFile from a physical file

I have a physical file and I want to pass it to my controller method that requires an IFormFile type (for unit testing).

I can't find any classes that instantiate the IFormFile interface which means I can't create one.

How can I convert my physical file into an IFormFile?

like image 602
Jamesla Avatar asked Jun 04 '16 09:06

Jamesla


People also ask

Where is the file path of IFormFile?

Inside the action method, the IFormFile contents are accessible as a Stream. So for IFormFile , you need to save it locally before using the local path. After this, you can get the local file path, namely filePath . In the case of a large file, isn't it taking a lot of time to get the file path after saving it locally?

What is IFormFile C#?

What is IFormFile. ASP.NET Core has introduced an IFormFile interface that represents transmitted files in an HTTP request. The interface gives us access to metadata like ContentDisposition, ContentType, Length, FileName, and more. IFormFile also provides some methods used to store files.


2 Answers

You can instantiate a FormFile. That implements IFormFile.

Example in .Net Core 3.1 (assume 'file' is physical path & file):

using var stream = new MemoryStream(File.ReadAllBytes(file).ToArray());
var formFile = new FormFile(stream, 0, stream.Length, "streamFile", file.Split(@"\").Last());
like image 65
Matt Frear Avatar answered Oct 03 '22 07:10

Matt Frear


Let's assume you have a controller method that accepts IFormInfo

[HttpPost]
public Task<IActionResult> Upload(IFormFile file) {

    FileDetails fileDetails = null;
    using (var reader = new StreamReader(file.OpenReadStream())) {
        var fileContent = reader.ReadToEnd();
        ContentDispositionHeaderValue parsedContentDisposition = null;
        if (ContentDispositionHeaderValue.TryParse(file.ContentDisposition, out parsedContentDisposition)) {
            fileDetails = new FileDetails {
                Filename = parsedContentDisposition.FileName,
                Content = fileContent
            };
        }
    }

    return Task.FromResult((IActionResult)fileDetails);

}

Using a mocking framework like Moq. You can use a physical file to mock the IFormFile

[TestMethod]
public async Task Controller_Should_Upload_FormFile() {
    // Arrange.
    var fileMock = new Mock<IFormFile>();
    var physicalFile = new FileInfo("filePath");
    var ms = new MemoryStream();
    var writer = new StreamWriter(ms);
    writer.Write(physicalFile.OpenRead());
    writer.Flush();
    ms.Position = 0;
    var fileName = physicalFile.Name;
    //Setup mock file using info from physical file
    fileMock.Setup(_ => _.FileName).Returns(fileName);
    fileMock.Setup(_ => _.Length).Returns(ms.Length);
    fileMock.Setup(_ => _.OpenReadStream()).Returns(ms);
    fileMock.Setup(_ => _.ContentDisposition).Returns(string.Format("inline; filename={0}", fileName));
    //...setup other members as needed.

    var sut = new MyController();
    var file = fileMock.Object;

    // Act.
    var result = await sut.Upload(file);

    //Assert.
    Assert.IsInstanceOfType(result, typeof(IActionResult));
}

The arranging of the mock can be even extracted into an extension method for reuse.

public static IFormFile AsMockIFormFile(this FileInfo physicalFile) {
    var fileMock = new Mock<IFormFile>();
    var ms = new MemoryStream();
    var writer = new StreamWriter(ms);
    writer.Write(physicalFile.OpenRead());
    writer.Flush();
    ms.Position = 0;
    var fileName = physicalFile.Name;
    //Setup mock file using info from physical file
    fileMock.Setup(_ => _.FileName).Returns(fileName);
    fileMock.Setup(_ => _.Length).Returns(ms.Length);
    fileMock.Setup(m => m.OpenReadStream()).Returns(ms);
    fileMock.Setup(m => m.ContentDisposition).Returns(string.Format("inline; filename={0}", fileName));
    //...setup other members (code removed for brevity)


    return fileMock.Object;
}

and used like

var physicalFile = new FileInfo("filePath");
IFormFile formFile = physicalFile.AsMockIFormFile();
like image 40
Nkosi Avatar answered Oct 03 '22 07:10

Nkosi