This project is read-only.

T4MVC and MVC4 WebAPI (ApiController)

Apr 30, 2012 at 11:44 PM
Edited Apr 30, 2012 at 11:47 PM

I'm working on an application which, as suggested by MVC4, is utilizing knockout.js and the WebAPI. One of the things I love about T4MVC is the ability to work with ActionResult objects rather than arbitrarily passing string values. So naturally, rather than write:

 

var url = "/api/PackSchedules?$top=" + pageSize + "&$skip=" + ((pageIndex - 1) * pageSize);

        $.getJSON(url, function (data) {
            viewModel.packSchedules(data);
        });

I wanted to write something along the lines of:

var url = "@Url.Action(MVC.PackSchedules.Get())?$top=" + pageSize + "&$skip=" + ((pageIndex - 1) * pageSize);

        $.getJSON(url, function (data) {
            viewModel.packSchedules(data);
        });

However, T4MVC doesn't appear to handle the ApiController at this time. Does anyone think I'm crazy or does this seem like a good use of the tool?

Thanks,

Vinney

 

EDIT: Removed extraneous code regions

May 1, 2012 at 12:22 AM

I think something could probably be done, though it might be a fair bit different from what happens with regular MVC controllers. In regular MVC, we rely on the action returning something that extends ActionResult, allowing us to use something that looks like regular calls to the action.

But in WebAPI, the methods don't return any common base class, so the same technique wouldn't work. We could still generate methods that have the same signature but are not actually the same method (so things like Go To Definition wouldn't work).

The other thing is that T4MVC relies on MVC framework methods to generate the path. e.g. when you call T4MVC's flavor of ActionLink, it in turns calls MVC's flavor, passing the controller/action names. But from what I can see in WebAPI, the path is typically hard coded. Or maybe there is a helper as well that most people just don't use?

May 3, 2012 at 5:42 PM

Yes, I see the intricacies involved. I think it's understandable that T4MVC woudn't provide the same functionality of a standard MVC action method but do you see any value in having the relative link available, similar to the way scripts and content are discovered with the Links namespace?

Thanks,
Vinney

May 3, 2012 at 7:20 PM

Can you clarify what you mean by the 'relative link' in this context? Thanks!

May 4, 2012 at 5:34 AM
Edited May 4, 2012 at 5:35 AM

Sure, to recap, the functionality I was looking for was the ability reference the  to replace

var url = '\api\products';

with

var url = @Url.Action(Api.Products());

Where "Api" might be a T4MVC namespace providing access to the WebAPI routes. Parameters could also be included in the same fashion.

var url = @Url.Action(Api.Products(1));

The idea is that the url variable could be used to retrieve data as in

$.getJSON(url, function(data) {...});

Does this seem sane? To be honest, I'm not exactly sure how kosher it is to have a WebAPI and MVC web client living in the same project but this is the way my first WebAPI project looks. I've also recently created a small javascript library to store the api urls and this seems to be working fine (for a magic string implementation). Thanks again for the consideration.

May 4, 2012 at 6:16 PM
Edited May 4, 2012 at 6:17 PM

I'm pretty new to WebAPI as well. I think it does make sense. But it seems WebAPI currently makes it pretty difficulty to generate links through routes. I just filed a bug on that http://aspnetwebstack.codeplex.com/workitem/121.

Stepping back, there are really two levels of hard coding things:

  1. Directly hard coding the path is the worst, as it makes assumptions on the route definitions.
  2. Going through a method like Url.RouteLink. Here, you don't hard code any route knowledge, but you just hard code controller/action names. The problem is that in WebAPI even doing that seems difficult right now.

Anyway, I think something can conceivably be done to improve this in T4MVC to improve things.

The hardest part is probably finding the time to work on it! Contributions are welcome :)

May 4, 2012 at 8:50 PM

I think T4MVC is a quintessential MVC package add-on. It's one of the first things I do when I click File > New Project (because I haven't ventured into creating custom VS project templates where I would surely include T4MVC as my default project template!). All that is to say, I would be glad to contribute to the project. My only hesitation is that my knowledge/experience with WebAPI and REST in general is lacking enough that I'm concerned I would rollout a somewhat naive solution. That said, let me see if I can architect a plan and I'll get back to you. Sound good?

May 7, 2012 at 2:41 AM

I think the key is to take scenarios one by one and see how some things can be changed into a T4MVC flavor. But in the case of WebAPI, you have to start with something that actually uses some API to produce path. So per that bug I filed, the non-T4MVC way is:

Url.RouteUrl(new { Controller = "PackSchedules", HttpRoute = true })

And presumably that can become

Url.Action(MVC.PackSchedule.Get())

And that would internally call the non-T4MVC one. So similar to what T4MVC does today, but with different underlying logic.

Sep 19, 2012 at 5:45 PM

Hi @davidebbo! I was just noticing that the MVC team added a fix for your bug report. Yay us! Does this fix make the WebAPI templating any more feasible? I'm afraid I do have to plead ignorance in this regard. Thanks!

Oct 31, 2012 at 11:18 PM

in fork RRoesler/WebAPI I have just committed an attempt to handle WebAPI controllers in T4MVC.

What I did was 

a) Used IsController to determine what type of controller was found (MVC or API)

b) In ProcessControllerActionMethods, for WebAPI Controller, look for HTTP Verbs to identify actions

c) For WebAPI actions, pretend that they return ActionResult regardless of what they actually return

d) For WebAPI, generate a new T4MVC class instead of extendings (with partial) the original controller

e) For WebAPI, the generated controller mocks are kinda like NoRealController generation

Kinda ugly which is why I'm not creating a pull request yet.

Nov 1, 2012 at 7:30 AM

@rroesler: the general direction sounds about right, as clearly the standard T4MVC approach won't work. If you get to a point that you feel good enough about, we can think about how to get it in!

Nov 2, 2012 at 8:09 PM

I just started tinkering with MVC4 and I wonder if we should change the approach that T4MVC takes?

Currently T4MVC extendeds the controller and overrides the action methods. One of the properties it adds is Actions, which is just a pointer to the static instance of the overloaded class.

What if we instead just create a separate class, like what is done for controller-less views, and define all actions there, and have the Actions properties and the MVC properties point to it. We also could make those actions return IT4MVCActionLink or something similar. A majority of the usage for T4MVC would stay the same and we would no longer have to overload the ActionResult classes. We could still use the same extension methods, and it would work with the WebApi since we are not overloading anymore.

Is there really any major advantage to overloading the Controller? I Might tinker with this idea over the next few weeks as I experiment with MVC4.

Nov 2, 2012 at 9:46 PM

I think the main thing we would lose is the ability to hit "Go to definition" on an action method in a T4MVC call, and have it actually go to the real action and not the generated code. That was the main reason behind the current inheritance design.

A similar one was refactoring. e.g. if you rename a controller action, the refactoring engine will successfully fix up the T4MVC calls that go to that action. At least it works for calls that come from .cs files, and not from views (since refactoring doesn't work in views - maybe with Reshaper it does?).

Does that make sense?

Now the big question is: are we paying too big of a price for these benefits, in term of code complexity and ability to deal with these new situations?

Nov 3, 2012 at 12:05 AM

I did something similar last year on T4MVC when it was still hosted with MvcContrib  (see rroesler/RRoeslerPatches1 under MvcContrib)

In my case, the driver was the fact that the T4MVC added parameter less methods broke some refactoring for me.

(I also created View references as constants and a few other things that I needed)

In this project, for WebAPI I did exactly what you suggested in rroesler/WebAPI.   The solution still have some problems.  For example, there is a problem between MVC routes and WebAPI routes which I still need to fix.

 

Nov 15, 2012 at 8:07 PM
Edited Nov 20, 2012 at 8:05 PM

I have an initial concept of WebAPI support, This is actually not MVC4 support since WebAPI can be added to an MVC3 project. If you guys want to check out the fork I created for it and give suggestions on areas I may have gone overboard on let me know.

http://t4mvc.codeplex.com/SourceControl/network/forks/mswainatwork/t4mvc?branch=webapi

[Edit]

I re-did my WebApi implementation. It now sits beside the current T4MVC instead of just heavily modifying it. This does cause code duplication to allow the two to co-exists, but hopefully if this pans out we can depreciate the old way.

Apr 17, 2013 at 10:45 AM
Hello,

I was looking for T4MVC for Web APIand was pointed to this thread.

Was any evolution on this? Is it dependent on next version of Web API?

thank You,
Miguel
Apr 19, 2013 at 8:15 AM
I have not had a chance to do any more work on T4MVC for WebAPI since that earlier posting. Currently our development efforts are focusing elsewhere where T4MVC can not contribute, so, for now, this is not on the top of my mind. Sorry.

Randy
May 22, 2013 at 12:24 PM
Hi All,

I have put together a small proof of concept of how this might work here.

The syntax looks like this:
var url = Url.HttpRouteUrl("DefaultApi", Api.SomeApi.Get(12));
The big problem with this implementation is, as David identified before, I was unable to override the actions on the api controller, which means refactoring does not work with the generated methods.

Does anyone have any better suggestions? Maybe using a lambda expression like this:
var url = Url.HttpRouteUrl("DefaultApi", x => SomeApiController.Get(12));
David - this may be a question for another thread, but do you have any plans to upgrade the T4MVCHostMvcApp to MVC4, or add an MVC4 version to the solution? The reason I ask is I've added a HttpRouteUrl() extension method which I think will clash with the one added in MVC4, and we could do with picking this up in a unit test.
May 22, 2013 at 6:35 PM
The first syntax is more in line with what T4MVC does today. I think we just have to accepts that we'll lose Got To Definition / Refactoring in the WebAPI case.

We can upgrade the test app to MVC4. That test app is a bit of a mess :)
May 24, 2013 at 9:02 AM
Thanks David, I'l make a start on updating the .tt file.
Aug 29, 2013 at 8:55 AM
did this get anywhere in the end???

regards
Aug 30, 2013 at 10:58 AM
I made a start, but I've been working on anther project for the past few months and have been short on time.

If you want to fork my repro and finish it off, I'll fill you in on what I've done and what is still to do.
Sep 6, 2013 at 3:45 PM
Hey Kevin, I'm interested in working on this feature. Can you let me know where you're at and what's left?
Sep 8, 2013 at 2:25 PM
@qntmfred, great. If you take a look at my proof of concept, you will get an idea of the approach I took:
  1. Generate a *.api.generated.cs file for each api controller in the project.
  2. Generate a derived T4MVC_* for each api controller.
  3. Override each action method to return an IT4MVCApiResult.
  4. Expose our derived controller classes in a new static Api class.
  5. Add new Url helpers which accept an IT4MVCApiResult.
Item 1 is almost done. It runs fine I have the .tt file open in tangible’s T4 Editor but throws a SerializationException if I don’t, so you’ll need to start here.

Let me know how you get on. If I have some time I’ll help you finish it off.