I'm currently trying to do something that was dead simple and straight forward in ASP.NET 4 however this ins't the case now in ASP.NET 5.
Previously to use the UrlHelper it was dead simple:
var urlHelper = new UrlHelper(HttpContext.Current.Request.RequestContext);
However I can't for the life of me wrap my head around how to use the new UrlHelper. I'm looking at the test cases and either I'm completely daft or I'm missing something and I can't seem to figure it out. Any help here in clearing up this would be great.
Update - Post RC2
As #deebo mentioned, you no longer can get an IUrlHelper directly from DI. Instead you need to inject an IUrlHelperFactory and an IActionContextAccessor into your class and use them to get the IUrlHelper instance as in:
public MyClass(IUrlHelperFactory urlHelperFactory, IActionContextAccessor actionAccessor)
{
this.urlHelperFactory = urlHelperFactory;
this.actionAccessor = actionAccessor;
}
public void SomeMethod()
{
var urlHelper = this.urlHelperFactory.GetUrlHelper(this.actionAccessor.ActionContext);
}
You need to also register the in your startup class (IUrlHelperFactory is already registered by default):
services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();
Bear in mind this will only work as long as the code where you get the actionContext is running after the MVC/routing middleware! (Otherwise actionAccessor.ActionContext would be null)
I have retrieved the IUrlHelper using the IServiceProvider in HttpContext.RequestServices.
Usually you will have an HttpContext property at hand:
In a controller action method you can do:
var urlHelper = this.Context.RequestServices.GetRequiredService<IUrlHelper>();
ViewBag.Url = urlHelper.Action("Contact", "Home", new { foo = 1 });
In a filter you can do:
public void OnActionExecuted(ActionExecutedContext context)
{
var urlHelper = context.HttpContext.RequestServices.GetRequiredService<IUrlHelper>();
var actionUrl = urlHelper.Action("Contact", "Home", new { foo = 1 });
//use actionUrl ...
}
Another option would be taking advantage of the built-in dependency injection, for example your controller could have a constructor like the following one and at runtime an IUrlHelper instance will be provided:
private IUrlHelper _urlHelper;
public HomeController(IUrlHelper urlHelper)
{
_urlHelper = urlHelper;
}
Thought I would share for the upcoming RC2 since the current answer won't work anymore then.
From RC 2 you will need to explicitly register IActionContextAccessor and IUrlHelperFactory
services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();
services.AddSingleton<IUrlHelperFactory, UrlHelperFactory>();
Then use the DI/service locator:
public EmailTagHelper(IUrlHelperFactory urlHelperFactory, IActionContextAccessor actionContextAccessor)
{
_urlHelper = urlHelperFactory.GetUrlHelper(actionContextAccessor.ActionContext);
}
I blogged about it here with regard to TagHelpers: http://devonburriss.me/asp-net-5-tips-urlhelper
In Startup.cs
services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();
services.AddSingleton<IUrlHelperFactory, UrlHelperFactory>();
services.AddScoped(it => it.GetService<IUrlHelperFactory>()
.GetUrlHelper(it.GetService<IActionContextAccessor>().ActionContext));
Alternatively
PM> Install-Package AspNetCore.IServiceCollection.AddIUrlHelper
In Startup.cs
services.AddUrlHelper();
If you just need the UrlHelper.Link method like I did, you don't even need the UrlHelper any more, just use Url.Link
A shorter version without constructing special Factory class
services.AddSingleton<IActionContextAccessor, ActionContextAccessor>()
.AddScoped<IUrlHelper>(sp => new UrlHelper(sp.GetRequiredService<IActionContextAccessor>().ActionContext));
Related
This has to be simple, but I'm going bug-eyed trying to find the answer. How does a controller action get a reference to the per-request ApplicationDbContext that was stashed in the Owin pipeline?
EDIT: Ok, I think I'm getting closer... or maybe not... All of my Googling seems to lead to this blog post, which sez to use:
var dbContext = context.Get<ApplicationDbContext>();
where context is apparently an instance of Microsoft.Owin.IOwinContext. So I tried:
var db = HttpContext.GetOwinContext().Get<ApplicationDbContext>();
But the Get<T> method requires a string key parameter. :(
And the answer (apparently) is... You need to add this using statement to get it to work:
using Microsoft.AspNet.Identity.Owin;
so a complete example would look like:
using Microsoft.AspNet.Identity.Owin;
public class HomeController : Controller
{
public ActionResult Index()
{
var context = HttpContext.GetOwinContext().Get<ApplicationDbContext>();
DoSomething(context); // Use the context object; do not dispose it!
return View();
}
}
I have a method on an ApiController that looks like this:
public IEnumerable<Items> GetSlideSets() {
IServiceClass serviceClass = new ServiceClass();
//...
Yes, I am aware that this is not good design but I'm addressing this issue in a different iteration.
At a certain point in my application I need to call this functionality from within the project itself so I thought I could simply reuse the controller (and why not, I can pluck it out of my IoC container). The only problem is that in this case, I need to inject my own implementation of IServiceClass, easy enough:
public IEnumerable<Items> GetSlideSets(IServiceClass serviceClass = null) {
serviceClass = serviceClass ?? new ServiceClass();
//...
Except now I am getting errors when calling this via a regular Api call Optionalparameter 'serviceClass' is not supported by FormatterParameterBinding.
I know that there are various attributes that control bindings. Is there one that I can put on the parameter to say it shouldn't bind.
Like others have mentioned, it's probably a better idea to inject the dependency in the constructor.
But if you really must avoid binding an action parameter, there isn't a built-in attribute but you can create one pretty easily. Here's what it could look like:
public class DontBindAttribute : ParameterBindingAttribute
{
public override HttpParameterBinding GetBinding(HttpParameterDescriptor parameter)
{
return new DontBindParameterBinding(parameter);
}
private class DontBindParameterBinding : HttpParameterBinding
{
public DontBindParameterBinding(HttpParameterDescriptor parameter) : base(parameter)
{
}
public override Task ExecuteBindingAsync(ModelMetadataProvider metadataProvider, HttpActionContext actionContext, CancellationToken cancellationToken)
{
actionContext.ActionArguments.Add(Descriptor.ParameterName, Descriptor.DefaultValue);
var completedTaskSource = new TaskCompletionSource<object>();
completedTaskSource.SetResult(null);
return completedTaskSource.Task;
}
}
}
You just need to apply the attribute to the parameter afterwards:
public IEnumerable<Items> GetSlideSets([DontBind] IServiceClass serviceClass = null)
I have a test where I pass in an object like so:
var repo = new ActualRepo();
var sut = new Sut(repo);
In my test, Repo has one method that I need to actually execute, whilst another method I want to mock out and not execute.
So for example, take this pseudocode:
var repo = new Mock<IRepo>();
repo.Setup(m => m.MethodIWantToCall()).WillBeExecuted();
repo.Setup(m => m.MethodIWantToMock()).Returns(false);
Using Moq, is this possible and how can it be done?
EDIT:
I've used TypeMock in the past and you can do something like.
Isolator.When(() => repo.MethodToIgnore()).WillBeIgnored();
Isolator.When(() => repo.MethodToActuallyRun()).WillBeExecuted();
Not too sure from the question if this is useful but it is possible to partially mock an object if the method that you want to mock is virtual.
public class Foo {
public string GetLive() {
return "Hello";
}
public virtual string GetMock() {
return "Hello";
}
}
public class Snafu {
private Foo _foo;
public Snafu(Foo foo) {
_foo = foo;
}
public string GetMessage() {
return string.Format("{0} {1}", _foo.GetLive(), _foo.GetMock());
}
}
[TestMethod]
public void NotMocked() {
var snafu = new Snafu(new Foo());
Assert.AreEqual("Hello Hello", snafu.GetMessage());
}
[TestMethod]
public void Mocked() {
var mockFoo = new Mock<Foo>();
mockFoo.Setup(mk => mk.GetMock()).Returns("World");
var snafu = new Snafu(mockFoo.Object);
Assert.AreEqual("Hello World", snafu.GetMessage());
}
You can't do this with Moq if you use the same object unless one of the method is virtual and you are basing your mock on a type rather than an interface.
That's because when you are passing a mock object based on an interface, you aren't passing a real object so it does not have access to the real methods of the object.
You are passing a dynamic proxy which will respond to methods it has been setup to respond to.
I believe TypeMock rewrites the assemblies at runtime to achieve this, something Moq definitively doesn't do.
If you want to achieve similar results with Moq:
You could mock both methods
You would have to extract both methods to different dependencies so as to mock one dependency and not the other.
You could have the method you need mocked be virtual, which would be the solution I would prefer.
EDIT : I edited my answer for correctness after reading AlanT's answer.
I'm building an ASP.NET MVC4 app. I'm not using any mocking framework and, if possible, would prefer not to at this point. My question is 2 parts.
I have a controller that uses a variable created in Global.asax. In the controller I access the variable like this.
HttpContext.Application["MyVar"]
1) Is this a best-practice for application wide variable usage? If not, what's the best way?
In an attempt to unit test this controller I added the following code (from here) to my test method.
MyController target = new MyController();
var request = new HttpRequest("", "http://example.com/", "");
var response = new HttpResponse(System.IO.TextWriter.Null);
var httpContext = new HttpContextWrapper(new HttpContext(request, response));
target.ControllerContext = new ControllerContext(httpContext, new RouteData(), target);
target.ControllerContext.HttpContext.Application["MyVar"] = new MyVar();
The problem is I can't add anything to Application. The last line of code doesn't seem to do anything and the collection remains empty. I've also tried this in VS's Immediate Window without success.
2) In the unit test, how can I add the application level variables the controller needs?
In general globals aren't good for testing. There are at least two approaches you could take.
Use a mocking framework like Pex/Moles, NMock, etc.
Use an inversion-of-control approach (NInject is my favorite). If class like a controller has an external dependency, it asks for the interface, typically in its constructor.
private readonly IApplicationSettings _settings;
public MyController(IApplicationSettings settings)
{
_settings = settings;
}
void someMethod()
{
_settings.Get("MyVar");
}
This way you can write real and test implementations.
public LiveAppSettings : IApplicationSettings
{
public string Get(string key)
{
return HttpContext.Current.Application[key];
}
}
With Ninject, you can bind either implementation at application startup:
var kernel = new StandardKernel();
kernel.Bind<IApplicationSettings>().To<LiveAppSettings>();
Is this a best-practice for application wide variable usage?
Best practice is a bit of a subjective notion and without fully explaining your scenario and what precisely are you trying to achieve I prefer not to discuss it.
We cannot discuss whether this is best practice but from what I can see it is not wrong either. It is not wrong because you are using the abstractions allowing the code to be unit tested.
In the unit test, how can I add the application level variables the controller needs?
You could use a mocking framework such as Rhino Mocks to mock the abstractions that the controller needs. Let's take as an example the following controller:
public class HomeController : Controller
{
public ActionResult Index()
{
var myVar = (MyVar)HttpContext.Application["MyVar"];
return Content(myVar.Foo);
}
}
and we would like to unit test the Index action. Here's a sample unit test:
[TestMethod]
public void Index_Action_Should_Retrieve_MyVal_From_AppState()
{
// arrange
var target = new HomeController();
var httpContext = MockRepository.GeneratePartialMock<HttpContextBase>();
var application = MockRepository.GeneratePartialMock<HttpApplicationStateBase>();
application.Expect(x => x["MyVar"]).Return(new MyVar { Foo = "bar" });
httpContext.Expect(x => x.Application).Return(application);
target.ControllerContext = new ControllerContext(httpContext, new RouteData(), target);
// act
var actual = target.Index() as ContentResult;
// assert
Assert.AreEqual("bar", actual.Content);
}
I'm working on a ASP.NET WebApi (Release Candidate) project where I'm consuming several DTOs that are marked with the [Serializable] attribute. These DTOs are outside of my control so I'm not able to modify them in any way. When I return any of these from a get method the resulting JSON contains a bunch of k__BackingFields like this:
<Name>k__BackingField=Bobby
<DateCreated>k__BackingField=2012-06-19T12:35:18.6762652-05:00
Based on the searching I've done this seems like a problem with JSON.NET's IgnoreSerializableAttribute setting and to resolve my issue I just need to set it globally as the article suggests. How do I change this setting globally in a ASP.NET Web api project?
I found easy way to get rid of k__BackingField in the names.
This fragment should be somewhere in the Application_Start() in Global.asax.cs:
JsonSerializerSettings jSettings = new Newtonsoft.Json.JsonSerializerSettings();
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings = jSettings;
Looks like the default setting takes care of it.
Since the library does not expose a static setter for the DefaultContractResolver, I suggest you create a static wrapper over JsonConvert and it's Serialize*/Deserialize* methods (at least the ones you use).
In your static wrapper you can define a static contract resolver:
private static readonly DefaultContractResolver Resolver = new DefaultContractResolver
{
IgnoreSerializableAttribute = true
};
This you can pass to each serialization method in the JsonSerializerSettings, inside your wrapper.
Then you call your class throughout your project.
The alternative would be to get the JSON.NET source code and adjust it yourself to use that attribute by default.
For me, the following fixed the issue with circular references and k__BackingField.
In your WebApiConfig add the following to the Register() method:
JsonSerializerSettings jSettings = new Newtonsoft.Json.JsonSerializerSettings {
ContractResolver = new DefaultContractResolver {
IgnoreSerializableAttribute = true
},
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
};
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings = jSettings;
Friends, don't declare properties like this:
public String DiscretionCode { get; set; }
But, create auxiliar vars, like old....
private String discretionCode;
public String DiscretionCode
{
get { return discretionCode;}
set { discretionCode = value; }
}