I was wondering if it's possible to use an extension method with asp.net webforms and nvelocity. I would like to set some defaults if the string value is null or empty.
Example of .vm file:
Example of my email body...
Billable Status: $billableStatus.Evaluate()
rest of my email body...
Attempted extension method:
public static class Helper
{
public static string Evaluate(this string value)
{
if (String.IsNullOrEmpty(value))
return "Not Provided";
else
return value;
}
}
Or is there an alternative to what I'm tryting to accomplish?
I don't think NVelocity can resolve extension methods with C#/VB.NET syntax sugar. What I do is register an instance of a helper in the velocity context:
var context = VelocityContext();
context.Put("helper", new Helper());
context.Put("billableStatus", "something");
...
and then in your template:
$helper.Evaluate($billableStatus)
You have to make your helper non-static for this to work, of course.
I came across something similar in past and I was looking for something more sophisticated and with more control. I found that NVelocity does provide a way to intercept the method and property calls but for that you will have to implement certain things. In order to make your custom interceptor you will need to implement NVelocity.IDuck. For example
public class MyClass : NVelocity.IDuck
{
public object GetInvoke(string propName)
{
....
}
public object Invoke(string method, params object[] args)
{
....
}
public void SetInvoke(string propName, object value)
{
....
}
}
Now any instance of MyClass will intercept and pass the method and property calls to our these three function implementation and give us a chance to resolve and return the output. You may notice from these three function signatures that in order to implement them we may need some reflection where we can locate respective methods on available extension types and execute them. If needed you can read following blog post for more details about going this way. NVelocity and extension methods
Related
I was looking at another question:
Exception is: InvalidOperationException - The current type, is an interface and cannot be constructed. Are you missing a type mapping?
Everyone scolded the person asking the question for 'doing it wrong'. But if you look at all the examples and sites describing this, they all describe injecting an interface into a Controller, typically via the constructor.
The problem here is that suppose I have a Web API which, for example returns a phrase in a different language:
http://mywebapi/api/SayHello/FR
The FR tells the WebAPI that we want Hello in French. I could easily use English, Chinese or any other language.
Now, I decide to build a set of Assemblies, one for each language, all implementing an interface called ILanguage. I make a Unity Container, put named type mappings in the config file (resolving the ILanguage interface with "FR" would return a ILanguage implemented by the French assembly, etc).
The code does NOT know when it's called WHICH implementation it's going to get. Injecting an ILanguage implementation into the Controller constructor seems wrong. Only when the URL is parsed and we get into the method do we see the "FR" parameter passed in, and that tells us to call:
container.Resolve<ILanguage>("FR")
to get the correct ILanguage interface for calling to return the appropriate phrase.
A dogmatic "never call container.Resolve" in your code anywhere, sounds very nice and purist, but it doesn't solve this problem. So, what is the recommended approach? It looks a lot like a ServiceLocator in the sense that we want to find a service dynamically using a 'key' of some kind, but I certainly do NOT want my Web API controller assembly having direct knowledge of all these little language assemblies. I have this working using the system above, but I'm wondering what all the DI/IoC purists would say about this code, and if they don't like it, how they solve the 'dynamic plug-in' problem in a Web API Controller.
I would recommend making your controllers accept a language factory (i.e. a Func<string, ILanguage>) that returns the ILanguage implementation based on the language code you pass into it.
The reason that a factory function should be favored over not declaring any dependencies in your constructor and instead calling container.Resolve() is that the latter obscures the fact that you depend on ILanguage, whereas taking a dependency on a Func<string, ILanguage> makes this very clear.
I.e.:
public interface ILanguage
{
string SayHello();
}
public class Program
{
public static void Main(string[] args)
{
UnityContainer container = new UnityContainer();
container.RegisterType<Func<string, ILanguage>>(new InjectionFactory(con => LanguageFactory));
//Use it:
MyController controller = container.Resolve<MyController>();
string result = controller.TalkToMe("en");
}
private static Func<string, ILanguage> LanguageFactory = delegate(string languageCode)
{
//Create the correct ILanguage here based on the languageCode.
//It's OK to call container.Resolve() here, for example to
//resolve named instances.
return (ILanguage)null;
};
}
public class MyController
{
private Func<string, ILanguage> _languageFactory;
public MyController(Func<string, ILanguage> languageFactory)
{
_languageFactory = languageFactory;
}
public string TalkToMe(string languageCode)
{
ILanguage language = _languageFactory(languageCode);
return language.SayHello();
}
}
As an alternative, you could also use the IUnityContainer that you get passed into the InjectionFactory to do the resolving in the language factory:
container.RegisterType<Func<string, ILanguage>>(new InjectionFactory(con => CreateLanguageFactory(con)));
//...
private static Func<string, ILanguage> CreateLanguageFactory(IUnityContainer container)
{
return delegate(string languageCode)
{
//Create the correct ILanguage here based on the languageCode.
ILanguage result = container.Resolve<ILanguage>(languageCode);
return result;
};
}
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 want to have one model & view that is served by multiple controllers in my ASP.NET MVC 3 app.
I'm implementing a system that interacts with the users' online calendar and I support Exchange, Google, Hotmail, Yahoo, Apple, ect... Each of these has wildly different implementations of calendar APIs, but I can abstract that away with my own model. I'm thinking that by implementing the polymorphism at the controller level I will be able to deal cleanly with the different APIs and authentication issues.
I have a nice clean model and view and I've implemented two controllers so far that prove I can read/query/write/update to both Exchange and Google: ExchangeController.cs and GoogleController.cs.
I have /Views/Calendar which contains my view code. I also have /Models/CalendarModel.cs that includes my model.
I want the test for which calendar system the user is using to happen in my ControllerFactory. I've implemented it like this:
public class CustomControllerFactory : DefaultControllerFactory
{
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType == typeof(CalendarController))
{
if(MvcApplication.IsExchange) // hack for now
return new ExchangeController();
else
return new GoogleController();
}
return base.GetControllerInstance(requestContext, controllerType);
}
}
and in my Application_Start:
ControllerBuilder.Current.SetControllerFactory(new CustomControllerFactory());
This works. If I got to http://.../Calendar this factory code works and the correct controller is created!
This worked beautifully and I did it without really understanding what I was doing. Now i think I got it but I want to make sure I'm not missing something. I really spent time searching for something like this and didn't find anything.
One thing that concerns me is that I figured I'd be able to have an inheritance relationship between CalendarController and ExchangeController/GoogleController like this:
public class ExchangeController : CalendarController
{
But if I do that I get:
The current request for action 'Index' on controller type 'GoogleController' is ambiguous between the following action methods:
System.Web.Mvc.ViewResult Index(System.DateTime, System.DateTime) on type Controllers.GoogleController
System.Web.Mvc.ActionResult Index() on type Controllers.CalendarController
Which bums me out because I wanted to put some common functionality on the base and now I guess I'll have to use another way.
Is this the right way to do have multiple controllers for one view/model? What else am I going to have to consider?
EDIT: More details on my impl
Based on the responses below (thanks!) I think I need to show some more code to make sure you guys see what I'm trying to do. My model is really just a data model. It starts with this:
/// <summary>
/// Represents a user's calendar across a date range.
/// </summary>
public class Calendar
{
private List<Appointment> appointments = null;
/// <summary>
/// Date of the start of the calendar.
/// </summary>
public DateTime StartDate { get; set; }
/// <summary>
/// Date of the end of the calendar
/// </summary>
public DateTime EndDate { get; set; }
/// <summary>
/// List of all appointments on the calendar
/// </summary>
public List<Appointment> Appointments
{
get
{
if (appointments == null)
appointments = new List<Appointment>();
return appointments;
}
set { }
}
}
Then my controller has the following methods:
public class ExchangeController : Controller
{
//
// GET: /Exchange/
public ViewResult Index(DateTime startDate, DateTime endDate)
{
// Exchange specific gunk. The MvcApplication._service thing is a temporary hack
CalendarFolder calendar = (CalendarFolder)Folder.Bind(MvcApplication._service, WellKnownFolderName.Calendar);
Models.Calendar cal = new Models.Calendar();
cal.StartDate = startDate;
cal.EndDate = endDate;
// Copy the data from the exchange object to the model
foreach (Microsoft.Exchange.WebServices.Data.Appointment exAppt in findResults.Items)
{
Microsoft.Exchange.WebServices.Data.Appointment a = Microsoft.Exchange.WebServices.Data.Appointment.Bind(MvcApplication._service, exAppt.Id);
Models.Appointment appt = new Models.Appointment();
appt.End = a.End;
appt.Id = a.Id.ToString();
...
}
return View(cal);
}
//
// GET: /Exchange/Details/5
public ViewResult Details(string id)
{
...
Models.Appointment appt = new Models.Appointment();
...
return View(appt);
}
//
// GET: /Exchange/Edit/5
public ActionResult Edit(string id)
{
return Details(id);
}
//
// POST: /Exchange/Edit/5
[HttpPost]
public ActionResult Edit(MileLogr.Models.Appointment appointment)
{
if (ModelState.IsValid)
{
Microsoft.Exchange.WebServices.Data.Appointment a = Microsoft.Exchange.WebServices.Data.Appointment.Bind(MvcApplication._service, new ItemId(appointment.Id));
// copy stuff from the model (appointment)
// to the service (a)
a.Subject = appointment.Subject
...
a.Update(ConflictResolutionMode.AlwaysOverwrite, SendInvitationsOrCancellationsMode.SendToNone);
return RedirectToAction("Index");
}
return View(appointment);
}
//
// GET: /Exchange/Delete/5
public ActionResult Delete(string id)
{
return Details(id);
}
//
// POST: /Exchange/Delete/5
[HttpPost, ActionName("Delete")]
public ActionResult DeleteConfirmed(string id)
{
Microsoft.Exchange.WebServices.Data.Appointment a = Microsoft.Exchange.WebServices.Data.Appointment.Bind(MvcApplication._service, new ItemId(id));
a.Delete(DeleteMode.MoveToDeletedItems);
return RedirectToAction("Index");
}
So it's basically the typical CRUD stuff. I've provided the sample from the ExchangeCalendar.cs version. The GoogleCalendar.cs is obviously similar in implementation.
My model (Calendar) and the related classes (e.g. Appointment) are what get passed from controller to view. I don't want my view to see details of what underlying online service is being used. I do not understand how implementing the Calendar class with an interface (or abstract base class) will give me the polymorphism I am looking for.
SOMEWHERE I have to pick which implementation to use based on the user.
I can either do this:
In my model. I don't want to do this because then my model gets all crufty with service specific code.
In the controller. E.g. start each controller method with something that redirects to the right implementation
Below the controller. E.g. as I'm suggesting above with a new controller factory.
The responses below mention "service layer". I think this is, perhaps, where I'm off the rails. If you look at the way MVC is done normally with a database, the dbContext represents the "service layer", right? So maybe what you guys are suggesting is a 4th place where I can do the indirection? For example Edit above would go something like this:
private CalendarService svc = new CalendarService( e.g. Exchange or Google );
//
// POST: /Calendar/Edit/5
[HttpPost]
public ActionResult Edit(MileLogr.Models.Appointment appointment)
{
if (ModelState.IsValid)
{
svc.Update(appointment);
return RedirectToAction("Index");
}
return View(appointment);
}
Is this the right way to do it?
Sorry this has become so long-winded, but it's the only way I know how to get enough context across...
END EDIT
I wouldn't do it this way. As Jonas points out, controllers should be very simple and are intended to coordinate various "services" which are used to respond to the request. Are the flows of requests really all that different from calendar to calendar? Or is the data calls needed to grab that data different.
One way to do this would be to factor your calendars behind a common calendar interface (or abstract base class), and then accept the calendar into the controller via a constructor parameter.
public interface ICalendar {
// All your calendar methods
}
public abstract class Calendar {
}
public class GoogleCalendar : Calendar {}
public class ExchangeCalendar : Calendar {}
Then within your CalendarController,
public class CalendarController {
public CalendarController(ICalendar calendar) {}
}
This won't work by default, unless you register a dependency resolver. One quick way to do that is to use NuGet to install a package that sets one up. For example:
Install-Package Ninject.Mvc3
I think this would be a better architecture. But suppose you disagree, let me answer your original question.
The reason you get the ambiguous exception is you have two public Index methods that are not distinguished by an attribute that indicates one should respond to GETs and one to POSTs. All public methods of a controller are action methods.
If the CalendarController isn't meant to be instantiated directly (i.e. it'll always be inherited), then I would make the Index method on that class protected virtual and then override it in the derived class.
If the CalendarController is meant to be instantiated on its own, and the other derived classes are merely "flavors" of it, then you need to make the Index method public virtual and then have each of the derived classes override the Index method. If they don't override it, they're adding another Index method (C# rules, not ours) and you need to distinguish them for MVC's sake.
I think you're on a dangerous path here. A controller should generally be as simple as possible, and only contain the "glue" between e.g. your service layer and the models/views. By moving your general calendar abstractions and vendor specific implementations out of the controllers, you get rid of the coupling between your routes and the calendar implementation.
Edit: I would implement the polymorphism in the service layer instead, and have a factory class in the service layer check your user database for the current user's vendor and instantiate the corresponding implementation of a CalendarService class. This should eliminate the need for checking the calendar vendor in the controller, keeping it simple.
What I mean by coupling to the routes is that your custom URLs is what is currently causing you problems AFAICT. By going with a single controller and moving the complexity to the service layer, you can probably just use the default routes of MVC.
As the other answers suggest, you really should refactor your code so as to not require the multiple controllers in the first place.
However, you can still have your controllers inherit from a base class controller - you simply need to make sure that when you register the routes in the Global.asax.cs, you use the overload that specifies which namespace to find the controllers and action methods for a given route
e.g.
routes.MapRoute(null, "{controller}/{action}", new[] { "Namespace.Of.Controllers.To.USe" });
ASP.NET MVC 2.0 will now, by default, throw an exception when an action attempts to return JSON in response to a GET request. I know this can be overridden on a method by method basis by using JsonRequestBehavior.AllowGet, but is it possible to set on a controller or higher basis (possibly the web.config)?
Update: Per Levi's comment, this is what I ended up using-
protected override JsonResult Json(object data, string contentType, System.Text.Encoding contentEncoding)
{
return Json(data, contentType, JsonRequestBehavior.AllowGet);
}
This, like other MVC-specific settings, is not settable via Web.config. But you have two options:
Override the Controller.Json(object, string, Encoding) overload to call Json(object, string, Encoding, JsonRequestBehavior), passing JsonRequestBehavior.AllowGet as the last argument. If you want this to apply to all controllers, then do this inside an abstract base controller class, then have all your controllers subclass that abstract class.
Make an extension method MyJson(this Controller, ...) which creates a JsonResult and sets the appropriate properties, then call it from your controller via this.MyJson(...).
There's another option. Use Action Filters.
Create a new ActionFilterAttribute, apply it to your controller or a specific action (depending on your needs). This should suffice:
public class JsonRequestBehaviorAttribute : ActionFilterAttribute
{
private JsonRequestBehavior Behavior { get; set; }
public JsonRequestBehaviorAttribute()
{
Behavior = JsonRequestBehavior.AllowGet;
}
public override void OnResultExecuting(ResultExecutingContext filterContext)
{
var result = filterContext.Result as JsonResult;
if (result != null)
{
result.JsonRequestBehavior = Behavior;
}
}
}
Then apply it like this:
[JsonRequestBehavior]
public class Upload2Controller : Controller
MVC 2 block Json for GET requests for security reasons. If you want to override that behavior, check out the overload for Json that accepts a JsonRequestBehavior parameter.
public ActionResult Index()
{
return Json(data, JsonRequestBehavior.AllowGet)
}
I also got this error when I first use MVC 2.0 using my old code in MVC 1.0. I use fiddler to identify the cause of the error. See the steps on how to troubleshoot it using Fidder -
http://www.rodcerrada.com/post/2011/07/11/jQuery-getJSON()-does-not-tirgger-the-callback-in-ASPNET-MVC-2.aspx
Is this is the security issue MVC2 was trying to address?
http://haacked.com/archive/2009/06/25/json-hijacking.aspx
If so, it seems like the vulnerability is only an issue if you are trying to do a json call to an outside website. If your MVC2 app is only making json calls to your own website (to fill jqgrids for example), shouldn't you be able to safely override the Json call in your base controller to always allow get?
Just change JSON code from :
$.getJson("methodname/" + ID, null, function (data, textStatus)
to:
$.post("methodname/" + ID, null, function (data, textStatus)
I have a number of permissions, and based on a set of conditions these permission determine if a user can see certain features. I have written a helper function for this as the logic in the view became quite extensive.
Essentially I'm looking for a function the same as Html.ActionLink that I can access from a class file (Ideally if I can access the Helper that would be great) So I can do somthing like so,
public static string GetAdminLinks()
{
if(PermCheck)
{
return(Html.ActionLink(...));
}
}
Any sugestions?
in controller:
Url.Action("Index", "Home", null, Request.Url.Scheme);
It largely depends on how your permission check is implemented (and of which information it needs to determine the user's permissions). Anyhow, I'd implement it as an extension to the HtmlHelper class.
Somewhere in your App_Code:
using System.Web.Mvc.Html;
public static class HtmlHelperExtensions {
public static string SecureActionLink(this HtmlHelper htmlHelper, string action, string controller){
if(PermCheck)
return htmlHelper.ActionLink(action, controller);
else
return string.Empty;
}
//add other ActionLink overrides if you like...
}
Then you'll be able to call the extension method from anywhere in your ViewPages without any code behind.