using HTTPContext variable in POCO Model class in asp.net MVC - asp.net-mvc

Controller uses HttpContext request object to get relevant information and passes it along to viewmodel.
string user = HttpContext.Request.Headers["abc"]
Question is how to pass the same information i.e. HttpContext to POCO model where i have to set some parameters. i can't user System.Web.MVC
public class Test
{
public string userA;
public Test()
{
userA = "Here I want to get the user from HttpContext and set it";
}
}
creating HTTPContextBase object using HTTPContext.Current throws error
"Request is not available in current context"
any help would be appreciated.thanks

Consider using a unmapped property (or a function that sets a private variable) in your model to store the value of whatever information you need from the httpcontext.
Your model should not know about the httpcontext. Models should be separated from the environment in which they are being used.
Another idea is that if you need to do business logic using a service layer where the service has context information passed to it by the controller:
http://www.asp.net/mvc/tutorials/older-versions/models-(data)/validating-with-a-service-layer-cs

While it is a very good idea not to bound your Controllers to the HttpContext (as scott.korin mentions) I've found that there's some times no way around it (like when testing Routes).
Here's the code that we use, that is based on Steve Sanderson's book "Pro ASP.NET MVC 3 Framework". Pay close attention to the CreateHttpContext method.
private void TestRouteMatch(string url, string controller, string action, object routeProperties = null, string httpMethod = "GET")
{
// Arrange
RouteCollection routes = new RouteCollection();
MvcApplication.RegisterRoutes(routes);
// Act - process the route
RouteData result = routes.GetRouteData(CreateHttpContext(url, httpMethod));
// Assert
Assert.IsNotNull(result);
Assert.IsTrue(TestIncomingRouteResult(result, controller, action, routeProperties));
}
private bool TestIncomingRouteResult(RouteData routeResult, string controller, string action, object propertySet = null)
{
Func<object, object, bool> valCompare = (v1, v2) =>
{
return StringComparer.InvariantCultureIgnoreCase.Compare(v1, v2) == 0;
};
bool result = valCompare(routeResult.Values["controller"], controller)
&& valCompare(routeResult.Values["action"], action);
if (propertySet != null)
{
PropertyInfo[] propInfo = propertySet.GetType().GetProperties();
foreach (PropertyInfo pi in propInfo)
{
if (!(routeResult.Values.ContainsKey(pi.Name)
&& valCompare(routeResult.Values[pi.Name],
pi.GetValue(propertySet, null))))
{
result = false;
break;
}
}
}
return result;
}
private void TestRouteFail(string url)
{
// Arrange
RouteCollection routes = new RouteCollection();
MvcApplication.RegisterRoutes(routes);
// Act - process the route
RouteData result = routes.GetRouteData(CreateHttpContext(url));
// Assert
Assert.IsTrue(result == null || result.Route == null);
}
private HttpContextBase CreateHttpContext(string targetUrl = null, string httpMethod = "GET")
{
// create the mock request
Mock<HttpRequestBase> mockRequest = new Mock<HttpRequestBase>();
mockRequest.Setup(m => m.AppRelativeCurrentExecutionFilePath).Returns(targetUrl);
mockRequest.Setup(m => m.HttpMethod).Returns(httpMethod);
// create the mock response
Mock<HttpResponseBase> mockResponse = new Mock<HttpResponseBase>();
mockResponse.Setup(m => m.ApplyAppPathModifier(
It.IsAny<string>())).Returns<string>(s => s);
// create the mock context, using the request and response
Mock<HttpContextBase> mockContext = new Mock<HttpContextBase>();
mockContext.Setup(m => m.Request).Returns(mockRequest.Object);
mockContext.Setup(m => m.Response).Returns(mockResponse.Object);
// return the mocked context
return mockContext.Object;
}

Related

ASP.NET MVC, HttpContext.Current is null while mocking a request

public async Task <ActionResult>Select(DWorkingTimeSelection dto) {
var session = HttpUtils.GetSeesion<User>("USER");
}
public static T GetSeesion<T>(string key) where T : class
{
if (HttpContext.Current == null)
{
return default(T);
}
return HttpContext.Current.Session[key] as T;
}
public async Task <ActionResult>Select(DWorkingTimeSelection dto) {
var session = HttpUtils.GetSeesion<User>("USER");
}
public static T GetSeesion<T>(string key) where T : class
{
if (HttpContext.Current == null)
{
return default(T);
}
return HttpContext.Current.Session[key] as T;
}
I use nunti to mock a request.
And I add the SessionStateItemCollection to the Controller 's ControllerContext .
I found that the HttpContext.Current is null but the Controller 's Session[]
is not null because it get from the Controller 's ControllerContext .
So what should I do to avoid the HttpContext.Current is null while mocking a request
You can mock the HttpContext:
public static HttpContext FakeHttpContext(HttpRequest request)
{
var stringWriter = new StringWriter();
var httpResponce = new HttpResponse(stringWriter);
var httpContext = new HttpContext(request, httpResponce);
var sessionContainer = new HttpSessionStateContainer(
"id",
new SessionStateItemCollection(),
new HttpStaticObjectsCollection(),
10,
true,
HttpCookieMode.AutoDetect,
SessionStateMode.InProc,
false);
httpContext.Items["AspSession"] =
typeof(HttpSessionState).GetConstructor(
BindingFlags.NonPublic | BindingFlags.Instance,
null,
CallingConventions.Standard,
new[] { typeof(HttpSessionStateContainer) },
null).Invoke(new object[] { sessionContainer });
return httpContext;
}
[TestMethod]
public void ActionTest()
{
var request = new HttpRequest(string.Empty, "url to the action that you are testing", string.Empty)
{
RequestType = "GET"
};
HttpContext.Current = FakeHttpContext(request);
var controller = new YourController();
//You need the get a Result property since it is an async action
var result = controller.ActionToTest(//the parameters that your action expects).Result;
Assert.IsNotNull(result);
}
EDIT (answering the questions in your comment):
In order tot get a session you need to call HttpContext.Current.Session and not the HttpContext.Current.Session["id"] because HttpContext.Current.Session["id"] tries to get an id key from your session.
Once you store it there it will be available through this call. You can test it:
HttpContext.Current.Session["id"] = 5;
Assert.AreEqual(HttpContext.Current.Session["id"],5);
Regarding the httpContext.Items statement:
(From MSDN)HttpContext.Items is a key/value collection that can be used to organize and share data between an IHttpModule interface and an IHttpHandler interface during an HTTP request.
The statement that you are asking for, simply crates a new HttpSessionState object by using reflection (because it has only internal constructors) associates it with the HttpSessionStateContainer that you created earlier and stores it in HttpContext.Items under AspSession. And an interesting thing is that HttpContext.Current.Session actually is a shortcut to HttpContext.Items["AspSession"]. So the assignment of HttpSessionState object to the AspSession key is the on that makes HttpContext.Current.Session to work.
Well,after mocking the HttpContext as Alex Art said .
Calling the following method will be fine.
var sessionItems = new SessionStateItemCollection();
sessionItems["SessionKey"] = new MyCustomObject();
SessionStateUtility.AddHttpSessionStateToContext(fakeHttpContext,
new HttpSessionStateContainer(SessionNameStorage.Suser,
sessionItems,
new HttpStaticObjectsCollection(),
20000,
true,
HttpCookieMode.AutoDetect,
SessionStateMode.InProc,
false
));

Unit Testing a RedirectToAction with parameter

I have an MVC Controller Class that I am trying to Unit Test.
The particular ActionResult is like this
public ActionResult Create(Shipment newShipment)
{
do some stuff to create a shipmentID
...
return RedirectToAction("AddUnit",newShipment.ShipmentID);
}
I have mocked up the controller context etc and now I want to test that the newShipment.ShipmentID passed to the RedirectToAction call is what I expect.
I have a test (with lots of mocking of things in the setup phase)
[Test]
public void CreateSuccess()
{
//Arrange
var shipment = new Shipment();
shipment.Widgets = 2; //Make sure it a valid shipment otherwise
//Act
var result = controller.Create(shipment) as RedirectToRouteResult;
//Assert
Assert.IsNotNull(result);
Assert.AreEqual("AddUnits", result.RouteValues["action"]);
Assert.IsNull(result.RouteValues["controller"]);
...
And now I want to find an Assert to check that the shipmentID I pass to RedirectToAction is the right one. How do I retrieve its value?
(I believe this code works for real (ie the actual view gets the correct shipmentID) but I want to write a unit test ).
Actually, RedirectToActions can take parameters; below is a simplified example of how I tested for correct parameters in one. I'm using NUnit & FluentAssertions here.
[HttpPost]
public ActionResult RedirectMethod()
{
return RedirectToAction("Index", "Home", new { parameter = "Value" });
}
and then the test:
[Test]
public void RedirectSetsExpectedParameters()
{
var result = controller.RedirectMethod();
var redirectResult = result.As<RedirectToRouteResult>();
var expectedRedirectValues = new RouteValueDictionary
{
{ "parameter", "Value" },
{ "action", "Index" },
{ "controller", "Home" }
};
redirectResult
.RouteValues
.ShouldBeEquivalentTo(expectedRedirectValues,
"The redirect should look as I expect, including the parameters");
}
Here i given one sample for Redirect to action
public ActionResult Signupsuccess(string account_code, string plan)
{
..........
do some stuff
return RedirectToAction("SubscriptionPlan", "Settings");
}
I have mocked up controllercontext and passed some parameter to RedirectToAction call from controller to test method.Finally it tested both the expected and actual
[TestMethod()]
public void SignupsuccessTest()
{
HomeController target = new HomeController(); // TODO: Initialize to an appropriate value
string account_code = "B898YB7"; // TODO: Initialize to an appropriate value
string plan = "Application-BASIC"; // TODO: Initialize to an appropriate value
var ControllerContext = new Mock<ControllerContext>();
var context = target.HttpContext;
ControllerContext.SetupGet(p => p.HttpContext.Session["MerchantID"]).Returns("15");
ControllerContext.SetupGet(p => p.HttpContext.Session["FriendlyIdentifier"]).Returns("3d649876-19f5-48d2-af03-ca89083ae712");
target.ControllerContext = controllerContext.Object;
var action = (RedirectToRouteResult)target.Signupsuccess(account_code, plan);
action.RouteValues["action"].Equals("SubscriptionPlan");
action.RouteValues["controller"].Equals("Settings");
Assert.AreEqual("SubscriptionPlan", action.RouteValues["action"]);
Assert.AreEqual("Settings", action.RouteValues["controller"]);
}
I Hope really it will helpful for you.Thank You

Unit Testing Custom Model Binder - Fake HttpContext Issue

I have the following unit test defined to test my model binder:
[TestMethod]
public void DateTime_Works() {
// Arrange
var controllerContext = FakeContext.GetAuthenticatedControllerContext(new Mock<Controller>().Object, "TestAdmin");
var values = new NameValueCollection {
{ "Foo.Date", "12/02/1964" },
{ "Foo.Hour", "12" },
{ "Foo.Minute", "00" },
{ "Foo.Second", "00" }
};
var bindingContext = new ModelBindingContext() { ModelName = "Foo", ValueProvider = new NameValueCollectionValueProvider(values, null) };
var binder = new DateAndTimeModelBinder();
// Act
var result = (DateTime)binder.BindModel(controllerContext, bindingContext);
// Assert
Assert.AreEqual(DateTime.Parse("1964-12-02 12:00:00"), result);
}
Here is the FakeContext class:
public static class FakeContext {
public static HttpContextBase GetHttpContext(string username) {
var context = new Mock<HttpContextBase>();
context.SetupGet(ctx => ctx.Request.IsAuthenticated).Returns(!string.IsNullOrEmpty(username));
return context.Object;
}
public static ControllerContext GetControllerContext(Controller controller) {
return GetAuthenticatedControllerContext(controller, null);
}
public static ControllerContext GetAuthenticatedControllerContext(Controller controller, string username) {
var httpContext = GetHttpContext(username);
return new ControllerContext(httpContext, new RouteData(), controller);
}
}
Within my model binder i call a utility method which has the following line in it:
HttpContext.Current.User.Identity.IsAuthenticated
This seems to always return false even when I pass a username in. I was wondering how the GetHttpContext method can be modified to mock this out aswell.
I'd appreciate the help. Thanks
You are mocking the IsAuthenticated property of the Request and not of the User Identity. Your mock is indicating that the request has been authenticated, but has nothing to do with the identity authentication.
Changing your mock up a little should fix your problem.
var identityMock = new Mock<IIdentity>();
identityMock.SetupGet( i => i.IsAuthenticated ).Returns( !string.IsNullOrEmpty(username));
var userMock = new Mock<IPrincipal>();
userMock.SetupGet( u => u.Identity ). Returns( identityMock.Object );
var context = new Mock<HttpContextBase>();
context.SetupGet( ctx => ctx.User ).Returns( userMock.Object );
Edit The more I thought about it the more I felt these mocks needed to be setup seperatly
Note, I have not executed this code. It should get you what you need however.
MSDN for Request.IsAuthenticated
http://msdn.microsoft.com/en-us/library/system.web.httprequest.isauthenticated.aspx
MSDN for User.Identity.IsAuthenticated
http://msdn.microsoft.com/en-us/library/system.security.principal.iidentity.isauthenticated.aspx
Hope this helps.
You could use Moq and follow the advice found here:
Moq: unit testing a method relying on HttpContext

Using Moq to test methods that accept non-primative arguments

I'm trying to write a test for an ASP.Net MVC controller action.
I'd like to test that the action invokes a particular method on an injected service, so I'm mocking the service and using .Verify.
So in the simple case, I have the following action in my controller:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(string title)
{
_cmsService.AddPage(title);
return View("Edit");
}
using the service interface...
public interface ICmsService
{
void AddPage(string request);
}
and the following test...
//Arrange
const string pageTitle = "Test Page";
var cmsService = new Mock<ICmsService>();
cmsService.Setup(service => service.AddPage(pageTitle));
var controller = new PageController(cmsService.Object);
//Act
var result = controller.Create(pageTitle) as ViewResult;
//Assert
cmsService.Verify(service => service.AddPage(pageTitle), Times.Once());
Now I want to refactor my service operation to use request and response objects...
public interface ICmsService
{
CmsServiceAddPageResponse AddPage(CmsServiceAddPageRequest request);
}
So I change my action accordingly...
public ActionResult Create(string title)
{
var request = new CmsServiceAddPageRequest()
{
PageName = title
};
var response = _cmsService.AddPage(request);
return View("Edit");
}
and also my test...
//Arrange
const string pageTitle = "Test Page";
var cmsService = new Mock<ICmsService>();
var request = new CmsServiceAddPageRequest() {PageName = pageTitle};
cmsService.Setup(service => service.AddPage(request));
var controller = new PageController(cmsService.Object);
//Act
var result = controller.Create(pageTitle) as ViewResult;
//Assert
cmsService.Verify(service => service.AddPage(request), Times.Once());
But now when I run the test, I get the following message...
TestCase 'Web.Test.PageControllerTest.CreateNewPagePost'
failed: Moq.MockException :
Invocation was performed more than once on the mock: service => service.AddPage(value(Web.Test.PageControllerTest+<>c__DisplayClass1).request)
at Moq.Mock.ThrowVerifyException(IProxyCall expected, Expression expression, Times times)
at Moq.Mock.VerifyCalls(Interceptor targetInterceptor, MethodCall expected, Expression expression, Times times)
at Moq.Mock.Verify[T,TResult](Mock mock, Expression`1 expression, Times times, String failMessage)
at Moq.Mock`1.Verify[TResult](Expression`1 expression, Times times)
PageControllerTest.cs(67,0): at Web.Test.PageControllerTest.CreateNewPagePost()
What should I be doing to test a method that accepts a non-primitive type?
Thanks
Sandy
I think a better alternative to the first answer would be to implement a custom matcher rather than change code to match your testing framework. From:http://code.google.com/p/moq/wiki/QuickStart
// custom matchers
mock.Setup(foo => foo.Submit(IsLarge())).Throws<ArgumentException>();
...
public string IsLarge()
{
return Match<string>.Create(s => !String.IsNullOrEmpty(s) && s.Length > 100);
}
If you override Equals in the CmsServiceAddPageRequest object it should compare them correctly.

How to mock the Request on Controller in ASP.Net MVC?

I have a controller in C# using the ASP.Net MVC framework
public class HomeController:Controller{
public ActionResult Index()
{
if (Request.IsAjaxRequest())
{
//do some ajaxy stuff
}
return View("Index");
}
}
I got some tips on mocking and was hoping to test the code with the following and RhinoMocks
var mocks = new MockRepository();
var mockedhttpContext = mocks.DynamicMock<HttpContextBase>();
var mockedHttpRequest = mocks.DynamicMock<HttpRequestBase>();
SetupResult.For(mockedhttpContext.Request).Return(mockedHttpRequest);
var controller = new HomeController();
controller.ControllerContext = new ControllerContext(mockedhttpContext, new RouteData(), controller);
var result = controller.Index() as ViewResult;
Assert.AreEqual("About", result.ViewName);
However I keep getting this error:
Exception
System.ArgumentNullException:
System.ArgumentNullException : Value
cannot be null. Parameter name:
request at
System.Web.Mvc.AjaxRequestExtensions.IsAjaxRequest(HttpRequestBase
request)
Since the Request object on the controller has no setter. I tried to get this test working properly by using recommended code from an answer below.
This used Moq instead of RhinoMocks, and in using Moq I use the following for the same test:
var request = new Mock<HttpRequestBase>();
// Not working - IsAjaxRequest() is static extension method and cannot be mocked
// request.Setup(x => x.IsAjaxRequest()).Returns(true /* or false */);
// use this
request.SetupGet(x => x.Headers["X-Requested-With"]).Returns("XMLHttpRequest");
var context = new Mock<HttpContextBase>();
context.SetupGet(x => x.Request).Returns(request.Object);
var controller = new HomeController(Repository, LoginInfoProvider);
controller.ControllerContext = new ControllerContext(context.Object, new RouteData(), controller);
var result = controller.Index() as ViewResult;
Assert.AreEqual("About", result.ViewName);
but get the following error:
Exception System.ArgumentException:
System.ArgumentException : Invalid
setup on a non-overridable member: x
=> x.Headers["X-Requested-With"] at Moq.Mock.ThrowIfCantOverride(Expression
setup, MethodInfo methodInfo)
Again, it seems like I cannot set the request header.
How do I set this value, in RhinoMocks or Moq?
Using Moq:
var request = new Mock<HttpRequestBase>();
// Not working - IsAjaxRequest() is static extension method and cannot be mocked
// request.Setup(x => x.IsAjaxRequest()).Returns(true /* or false */);
// use this
request.SetupGet(x => x.Headers).Returns(
new System.Net.WebHeaderCollection {
{"X-Requested-With", "XMLHttpRequest"}
});
var context = new Mock<HttpContextBase>();
context.SetupGet(x => x.Request).Returns(request.Object);
var controller = new YourController();
controller.ControllerContext = new ControllerContext(context.Object, new RouteData(), controller);
UPDATED:
Mock Request.Headers["X-Requested-With"] or Request["X-Requested-With"] instead of Request.IsAjaxRequest().
For anyone using NSubstitute I was able to modify the above answers and do something like this... (where Details is the Action method name on the controller)
var fakeRequest = Substitute.For<HttpRequestBase>();
var fakeContext = Substitute.For<HttpContextBase>();
fakeRequest.Headers.Returns(new WebHeaderCollection { {"X-Requested-With", "XMLHttpRequest"}});
fakeContext.Request.Returns(fakeRequest);
controller.ControllerContext = new ControllerContext(fakeContext, new RouteData(), controller);
var model = new EntityTypeMaintenanceModel();
var result = controller.Details(model) as PartialViewResult;
Assert.IsNotNull(result);
Assert.AreEqual("EntityType", result.ViewName);
Here is a working solution using RhinoMocks. I've based it on a Moq solution I found at http://thegrayzone.co.uk/blog/2010/03/mocking-request-isajaxrequest/
public static void MakeAjaxRequest(this Controller controller)
{
MockRepository mocks = new MockRepository();
// Create mocks
var mockedhttpContext = mocks.DynamicMock<HttpContextBase>();
var mockedHttpRequest = mocks.DynamicMock<HttpRequestBase>();
// Set headers to pretend it's an Ajax request
SetupResult.For(mockedHttpRequest.Headers)
.Return(new WebHeaderCollection() {
{"X-Requested-With", "XMLHttpRequest"}
});
// Tell the mocked context to return the mocked request
SetupResult.For(mockedhttpContext.Request).Return(mockedHttpRequest);
mocks.ReplayAll();
// Set controllerContext
controller.ControllerContext = new ControllerContext(mockedhttpContext, new RouteData(), controller);
}
Is AjaxRequest is an extension method. So you can do it the following way using Rhino:
protected HttpContextBase BuildHttpContextStub(bool isAjaxRequest)
{
var httpRequestBase = MockRepository.GenerateStub<HttpRequestBase>();
if (isAjaxRequest)
{
httpRequestBase.Stub(r => r["X-Requested-With"]).Return("XMLHttpRequest");
}
var httpContextBase = MockRepository.GenerateStub<HttpContextBase>();
httpContextBase.Stub(c => c.Request).Return(httpRequestBase);
return httpContextBase;
}
// Build controller
....
controller.ControllerContext = new ControllerContext(BuildHttpContextStub(true), new RouteData(), controller);
Looks like you are looking for this,
var requestMock = new Mock<HttpRequestBase>();
requestMock.SetupGet(rq => rq["Age"]).Returns("2001");
Usage in Controller :
public ActionResult Index()
{
var age = Request["Age"]; //This will return 2001
}
In current .NET (v 5):
var controller = new SomeController(); // SomeController that inherits Microsoft.AspNetCore.Mvc.ControllerBase
var httpContext = new DefaultHttpContext(); // DefaultHttpContext class is part of Microsoft.AspNetCore.Http namespace
httpContext.Request.Headers.Add("origin", "0.0.0.1"); // Add your custom headers to request
controller.ControllerContext.HttpContext = httpContext;
You need to mock HttpContextBase and put it into your ControllerContext property, like that:
controller.ControllerContext =
new ControllerContext(mockedHttpContext, new RouteData(), controller);
To make IsAjaxRequest() to return false during Unit test you need to setup Request Headers as well as request collection value both in your test method as given below:
_request.SetupGet(x => x.Headers).Returns(new System.Net.WebHeaderCollection { { "X-Requested-With", "NotAjaxRequest" } });
_request.SetupGet(x=>x["X-Requested-With"]).Returns("NotAjaxRequest");
The reason for setting up both is hidden in implementation of IsAjaxRequest() which is given below:
public static bool IsAjaxRequest(this HttpRequestBase request)<br/>
{
if (request == null)
{
throw new ArgumentNullException("request");
}
return ((request["X-Requested-With"] == "XMLHttpRequest") || ((request.Headers != null) && (request.Headers["X-Requested-With"] == "XMLHttpRequest")));
}
It uses both request Collection and header this is why we need to create setup for both Header and Request Collection.
this will make the request to return false when it is not a ajax request. to make it return true you can do the following:
_httpContext.SetupGet(x => x.Request["X-Requested-With"]).Returns("XMLHttpRequest");
I found other way to add a HttpRequestMessage object into your request during Web API as follow
[Test]
public void TestMethod()
{
var controllerContext = new HttpControllerContext();
var request = new HttpRequestMessage();
request.Headers.Add("TestHeader", "TestHeader");
controllerContext.Request = request;
_controller.ControllerContext = controllerContext;
var result = _controller.YourAPIMethod();
//Your assertion
}
(A bit late to the party but I went for a different route so thought I'd share)
To go for a pure code/mocking way of testing this without creating mocks for Http classes I implemented an IControllerHelper which has an Initialise method which takes the Request as a parameter and then exposed properties I want eg:
public interface IControllerHelper
{
void Initialise(HttpRequest request);
string HostAddress { get; }
}
public class ControllerHelper : IControllerHelper
{
private HttpRequest _request;
public void Initialise(HttpRequest request)
{
_request = request;
}
public string HostAddress => _request.GetUri().GetLeftPart(UriPartial.Authority);
}
Then in my controller I call initialise at the start of the method:
_controllerHelper.Initialise(Request);
And then my code is only dependent on mockable dependacies.
return Created(new Uri($"{_controllerHelper.HostName}/api/MyEndpoint/{result.id}"), result);
For functional tests I just override the iControllerHelper in the composition for a substitute.

Resources