I have the following code for mocking the HttpContextAccessor. Most of it works fine but the area that I can’t get to work as expected is getting form values, specifically when trying to get them while iterating over the Keys collection. I put a breakpoint on the AddFormFieldsOrFile
method where it creates the new requestForm and when I mouse over that, it shows me an object with properties like Count, Keys, and Store and it has the values I added to it.
But if I put a breakpoint on the code where it’s iterating over the keys and look at the Request.Form mock, it looks different. The Store property is gone and I don’t see how to access the values based on the key.
If I let it continue, the value comes back as an empty string. So, I’m assuming I am not setting up the requestForm mock correctly.
public class MockHttpContextAccessor
{
public Mock<IHttpContextAccessor> ContextAccessor { get; private set; }
private FormFileCollection fileCollection;
private FormCollection requestForm;
private List<string> keys = new List<string>();
public MockHttpContextAccessor()
{
var requestFeature = new HttpRequestFeature();
var features = new FeatureCollection();
features.Set<IHttpRequestFeature>(requestFeature);
ContextAccessor = new Mock<IHttpContextAccessor>();
var session = new MockHttpSession();
var context = new DefaultHttpContext(features);
fileCollection = new FormFileCollection();
requestForm = new FormCollection(new Dictionary<string, StringValues>(), fileCollection);
ContextAccessor.Setup(x => x.HttpContext).Returns(context);
ContextAccessor.Setup(x => x.HttpContext.Session).Returns(session);
ContextAccessor.Setup(x => x.HttpContext.Request.Path).Returns("/path");
ContextAccessor.Setup(x => x.HttpContext.Request.Form).Returns(requestForm);
ContextAccessor.Setup(x => x.HttpContext.Request.Form.Files).Returns(requestForm.Files);
ContextAccessor.Setup(x => x.HttpContext.Request.Form.Keys).Returns(keys);
ContextAccessor.Setup(x => x.HttpContext.Request.Headers).Returns(new Mock<IHeaderDictionary>().Object);
}
public void AddRequestBody(string content)
{
ContextAccessor.Setup(x => x.HttpContext.Request.Body).Returns(new MemoryStream(System.Text.Encoding.UTF8.GetBytes(content)));
}
public void AddQueryStringParameters(Dictionary<string, string> p)
{
ContextAccessor.Setup(x => x.HttpContext.Request.QueryString).Returns(new QueryString("?" + string.Join("&", p.Select(x => $"{x.Key}={x.Value}"))));
}
public void ClearQueryStringParameters()
{
ContextAccessor
.Setup(x => x.HttpContext.Request.QueryString)
.Returns(new QueryString("?"));
}
public void SetDefaultFileUpload(string content = "some content", string filename = "filename.pdf", string formFieldID = "id_from_form")
{
var stream = new MemoryStream();
var writer = new StreamWriter(stream);
writer.Write(content);
writer.Flush();
stream.Position = 0;
IFormFile file = new FormFile(stream, 0, stream.Length, formFieldID, filename);
var formContents = new Dictionary<string, StringValues>();
AddFormFieldsOrFile(formContents, new List<IFormFile> { file });
}
public void AddFormFieldsOrFile(Dictionary<string, StringValues> fields, List<IFormFile> files = null)
{
if (files != null && files.Any())
{
ContextAccessor.Object.HttpContext.Request.Headers.Add("Content-Type", "multipart/form-data");
fileCollection.AddRange(files);
}
requestForm = new FormCollection(fields, fileCollection);
foreach (var field in fields)
{
keys.Add(field.Key);
}
}
public void ClearFormFiles()
{
fileCollection.Clear();
}
}
Here’s how I’m setting it up in my test.
[SetUp]
public override async Task SetUp()
{
_httpContextAccessor.AddFormFieldsOrFile(new Dictionary<string, StringValues>()
{
{"workingWithAgency", new StringValues("66199")}
});
await base.SetUp();
}
And finally, the code that I’m trying to test.
private List<SpecifiedByRecord> getFormFieldContacts(string name)
{
var retval = new List<SpecifiedByRecord>();
foreach (var key in _context.Request.Form.Keys)
if (key.Contains(name))
{
var val = _context.Request.Form[key].ToString();
var els = val.Split('^');
retval.Add(new SpecifiedByRecord {Id = els[0], Name = els[1]});
}
return retval;
}