1

SO, I have 20+ Actions in a controller as here below:

public  ActionResult DoThis()
        {
            Image img = Image.FromFile("DoThis.png");
            //some other stuff to be done.
            return View();
        }
public  ActionResult DoThat()
        {
            Image img = Image.FromFile("DoThat.png");
            //some other stuff to be done.
            return View();
        }

I have a view which I want to show ActionLink for each action that is placed in my controller with assigned picture to the action, let say this:

@foreach
{
   <div class="col-sm-4">
    <div class="product-image-wrapper">
        <div class="single-products">
            <div class="productinfo text-center">
                <img src="the image assigned to the controller actions" alt="" />
                <h3 style="font-family:'Myriad عربي'">Action Name ؟</h3>
                <a href="@URL.Action("The acion link from controller")" class="btn btn-default add-to-cart">Click Here</a>
            </div>
        </div>
    </div>
</div>
}

Is that possible or I am asking too much?

Coding Freak
  • 418
  • 1
  • 8
  • 27
  • 1
  • You can always use reflection to get the names of each method in the controller. Not really clear what your wanting to do and why? Why not just create a collection of items containing properties for the method and associated image? –  Jan 18 '17 at 07:56
  • I just want add links to my actions in controller dynamically. I mean I don't want to write `@URL.Action` for every action in my controller in the view. Is that possible? Some times the amount of those actions in my controllers may increase or decrease that should be taken care of automatically in my view. – Coding Freak Jan 18 '17 at 07:58
  • @StephenMuecke I have a question of mine unanswered, would you please look at it and have your points of view as far as I need to solve the problem so badly. Thank you. Here is the link for the question. [Question](http://stackoverflow.com/questions/41692795/is-there-anyway-to-make-one-image-out-of-3-image-urls-using-asp-net-mvc) – Coding Freak Jan 18 '17 at 08:32
  • An MVC controller is not the place to be "doing stuff with an image", that is generally for services that are injected into the controller. You can solve this by creating a [strategy](http://stackoverflow.com/a/1501517/181087) of services that each do something separate with the image, and refactoring your controller to be a single Action method with a string parameter that determines which action to perform on the image (and thus which service to activate). See [this](http://stackoverflow.com/a/31971691/181087) for another example. Creating the list of links is then trivial. – NightOwl888 Jan 18 '17 at 09:10
  • @NaserDostdar, Sorry, can't help with that one. There are plenty of plugins that allow you to convert a view to pdf ( iTextSharp, Rotiva etc), and I assume that there are some that will convert to Jpeg –  Jan 19 '17 at 02:20
  • @StephenMuecke I can make an Image out of a view with `Html2Canvas` but the only thing I am confused how can I make an image out of a view without rendering a view to `DOM`. It is like generating an image out of a view on the fly. Lets say in my action controller `Image img = Image.FromView("ViewName")`. Is that possible in any way? – Coding Freak Jan 19 '17 at 07:27

2 Answers2

3

Here's one way to get a list of ActionDescriptor[] for all actions on your controller:

@{
    var descriptor = new ReflectedControllerDescriptor(this.ViewContext.Controller.GetType());
    var actions = descriptor.GetCanonicalActions();
}

@foreach (var action in actions)
{
    <div>
        @Html.ActionLink("click me", action.ActionName)
    </div>
}

Now of course this will get a list of all actions on the current controller. If on the other hand you want to get only some specific actions, you could decorate them with some marker attribute and then filter the retrieved actions to only those having the attribute:

public class MyActionAttribute: Attribute
{
}

...

public class HomeController: Controller
{
    public ActionResult Index()
    {
        return View();
    }

    [MyAction]
    public ActionResult DoThis()
    {
        Image img = Image.FromFile("DoThis.png");
        //some other stuff to be done.
        return View();
    }

    [MyAction]
    public ActionResult DoThat()
    {
        Image img = Image.FromFile("DoThat.png");
        //some other stuff to be done.
        return View();
    }
}

and then:

@{
    var descriptor = new ReflectedControllerDescriptor(this.ViewContext.Controller.GetType());
    var actions = descriptor.GetCanonicalActions().Where(desc => desc.GetCustomAttributes(typeof(MyActionAttribute), true).Any());
}
Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • Darin Thank you for your answer. How can I set an Image foreach controller action in my view? I mean the picture should belong to the controller – Coding Freak Jan 18 '17 at 08:13
  • I am not sure that I understand what you are asking. You could use the `` element if you want to display the image: ``. This of course assumes that your controller action returns an image content type and not html. – Darin Dimitrov Jan 18 '17 at 08:16
  • I mean is there any way to assign an image to a controller action and then access that assigned picture to the controller in my view? Like I should have different images for each action in my controller and then pass it to the view with the action link in my view? – Coding Freak Jan 18 '17 at 08:19
  • What do you mean *assign an image to a controller action*? This doesn't really make much sense. A controller action could return an image result (instead of a view result) which will allow you to display this image using an `` tag. – Darin Dimitrov Jan 18 '17 at 08:20
  • 1
    @NaserDostdar - You cannot with your current implementation (`Image img = Image.FromFile("DoThis.png");` is just assigning a local variable in the method). One option would be to use an attribute as per Darin's suggestion and include a property for the image file - e.g. `[MyAction(Image="DoThis.png")]` and then use reflection to read the attribute property value –  Jan 18 '17 at 08:22
  • Well I think I am not able to tell you what I want to achieve. I just wanna show an Image for each controller action in my view together with their links. and that image should only be part of one action not many – Coding Freak Jan 18 '17 at 08:24
  • @StephenMuecke Solved the issue +1 for your useful comment. – Coding Freak Jan 18 '17 at 08:29
1

Well, you can certainly get the methods of a certain class via reflection:

public List<string> GetActionNames()
{
    return typeof(HomeController)
        .GetMethods(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance)
        .Where(method => method.ReturnType.IsSubclassOf(typeof(ActionResult)) || method.ReturnType == typeof(ActionResult))
        .Select(method => method.Name)
        .ToList();
}

This will return the names of all actions defined on your controller, where anything returning an ActionResult-compatible type is considered an action method and nothing else is. However, you should consider the following:

  • How will you decide what to bind to which parameter,
  • How will you handle overloaded methods,
  • You should refine this logic based on any security needs and other restrictions,
  • You should filter them further if any of the methods is a non-HttpGet, you could do this by filtering the methods by not having an HttpPost attribute on them (this gets even more complicated if you are dealing with an ApiController, where you should also consider the name prefix based method convention).

Generally speaking, the first bulletpoint is of most concern, you will be better off by just typing the links by hand rather than trying to figure out a reliable and general way of solving it. So I would only advise you to use such a logic if you can be sure that the aforementioned things are not something that you have to care about.

Balázs
  • 2,929
  • 2
  • 19
  • 34
  • I up voted your answer and will make use of your answer for my project but as far as your answer came second I cannot accept it as an answer. Thank you anyways! – Coding Freak Jan 18 '17 at 08:25