Calling an Action in custom Module?

Topics: Troubleshooting
Feb 9, 2012 at 2:48 AM

Hi all, I can’t manage to call my control action in my custom module from my view? The code is:

Controller: [***sorry, insert code snippet not working***]

using System.Linq;
using System.Web.Mvc;
using Orchard.UI.Admin;
using Donation.Services;
using Donation.Models;
using Orchard.Localization;
using Orchard.Mvc.AntiForgery;

namespace Donation.Controllers
{
    [Admin]
    public class DonationController : Controller
    {
        private readonly MemberService _memberService;

        public DonationController(MemberService memberService){
            _memberService = memberService;
        }

        public Localizer T { get; set; }

        [HttpPost]
        [ValidateAntiForgeryTokenOrchard]
        public ActionResult Remove(int donationId)
        {
            var donation = _memberService.GetMemberDonations(donationId);

            if (donation == null)
                return HttpNotFound();

            _memberService.RemoveDonation(donation);

            //Services.Notifier.Information(T("Donation was successfully deleted"));
            return Redirect(Url.RouteUrl("test"));
        }
    }
}

View:

@model Donation.ViewModels.EditMemberViewModel
 
<fieldset>
    <legend>Donations</legend>
    <div class="editor-label">
        @Html.LabelFor(model => model.Lifetime, T("Lifetime Member"))
    </div>
    <div class="editor-field">
        @Html.CheckBoxFor(model => model.Lifetime)
        @Html.ValidationMessageFor(model => model.Lifetime)
    </div>
   
    <table>
        <tr>
            <th>
                Transaction ID
            </th>
            <th>
                Spon/Don/Mem
            </th>
            <th>
                Project ID
            </th>
            <th>
                Amount
            </th>
            <th>
                Date Paid
            </th>
            <th></th>
        </tr>
        @foreach (var don in Model.Donations)
        {
            <tr>           
            @*Html.TextBoxFor(d => don.Id)*@
            <td>
            @Html.TextBoxFor(d => don.TransactionId)
            </td>
            <td>
            @Html.TextBoxFor(d => don.Code)
            </td>
            <td>
            @Html.TextBoxFor(d => don.ProjectId)
            </td>
            <td>
            @Html.TextBoxFor(d => don.Amount)
            </td>
            <td>
            @Html.TextBoxFor(d => don.PaidDate)
            @Html.ActionLink("test", "Remove", new { don.Id })
            </td>
            <td>
                @using (Html.BeginFormAntiForgeryPost(Url.Action("Remove", "Donation", new { area = "Donation" }), FormMethod.Post))
                {
                    @Html.Hidden("donationId", (int)don.Id)
                    <button type="submit">Remove</button>
                }
            </td>
            </tr>
        }
    </table>
</fieldset>

Any thoughts? Cheers Dyr

Feb 9, 2012 at 3:00 AM

Something looks a bit wrong because you're trying to put a form inside a form, that'll never work.

Feb 14, 2012 at 2:50 AM

Ok, this is what I have:

 

@model Donation.ViewModels.EditMemberViewModel

@using (Html.BeginFormAntiForgeryPost())
{ 
<fieldset>
    <legend>Donations</legend>
    <div class="editor-label">
        @Html.LabelFor(model => model.Lifetime, T("Lifetime Member"))
    </div>
    <div class="editor-field">
        @Html.CheckBoxFor(model => model.Lifetime)
        @Html.ValidationMessageFor(model => model.Lifetime)
    </div>
    
    <table>
        <tr>
            <th>
                Transaction ID
            </th>
            <th>
                Spon/Don/Mem
            </th>
            <th>
                Project ID
            </th>
            <th>
                Amount
            </th>
            <th>
                Date Paid
            </th>
            <th></th>
        </tr>
        @foreach (var don in Model.Donations)
        {
            <tr>            
            @*Html.TextBoxFor(d => don.Id)*@
            <td>
            @Html.TextBoxFor(d => don.TransactionId)
            </td>
            <td>
            @Html.TextBoxFor(d => don.Code)
            </td>
            <td>
            @Html.TextBoxFor(d => don.ProjectId)
            </td>
            <td>
            @Html.TextBoxFor(d => don.Amount)
            </td>
            <td>
            @Html.TextBoxFor(d => don.PaidDate)
            </td>
            <td>
                @*Url.Action("Remove", "Donation", new { area = "Donation" })*@

                @Html.ActionLink("Remove", "Remove", "Donation", new { Area = "Donation", donationId = don.Id }, null)
            </td>
            </tr>
        }
    </table>
</fieldset>
}

 

But I get this error [Controller code is still the same as above]:

Server Error in '/Orc' Application.

None of the constructors found with policy 'Orchard.Environment.AutofacUtil.DynamicProxy2.ConstructorFinderWrapper' on type 'Donation.Controllers.DonationController' can be invoked with the available services and parameters:
Constructor 'Void .ctor(Donation.Services.MemberService)' parameter resolution failed at parameter 'Donation.Services.MemberService memberService'.

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: Autofac.Core.DependencyResolutionException: None of the constructors found with policy 'Orchard.Environment.AutofacUtil.DynamicProxy2.ConstructorFinderWrapper' on type 'Donation.Controllers.DonationController' can be invoked with the available services and parameters:
Constructor 'Void .ctor(Donation.Services.MemberService)' parameter resolution failed at parameter 'Donation.Services.MemberService memberService'.

Source Error:

Line 24:                 var key = new KeyedService(serviceKey, typeof (T));
Line 25:                 object value;
Line 26:                 if (workContext.Resolve<ILifetimeScope>().TryResolve(key, out value)) {
Line 27:                     instance = (T) value;
Line 28:                     return true;


Source File: C:\orchard\src\Orchard\Mvc\OrchardControllerFactory.cs    Line: 26

Stack Trace:

[DependencyResolutionException: None of the constructors found with policy 'Orchard.Environment.AutofacUtil.DynamicProxy2.ConstructorFinderWrapper' on type 'Donation.Controllers.DonationController' can be invoked with the available services and parameters:
Constructor 'Void .ctor(Donation.Services.MemberService)' parameter resolution failed at parameter 'Donation.Services.MemberService memberService'.]
   Autofac.Core.Activators.Reflection.ReflectionActivator.ActivateInstance(IComponentContext context, IEnumerable`1 parameters) +578
   Autofac.Core.Resolving.ComponentActivation.Activate(IEnumerable`1 parameters) +89
   Autofac.Core.Resolving.ComponentActivation.Execute(IEnumerable`1 parameters) +141
   Autofac.Core.Resolving.ResolveOperation.Resolve(ISharingLifetimeScope activationScope, IComponentRegistration registration, IEnumerable`1 parameters) +246
   Autofac.Core.Lifetime.LifetimeScope.Resolve(IComponentRegistration registration, IEnumerable`1 parameters) +276
   Autofac.ResolutionExtensions.TryResolve(IComponentContext context, Service service, IEnumerable`1 parameters, Object& instance) +120
   Orchard.Mvc.OrchardControllerFactory.TryResolve(WorkContext workContext, Object serviceKey, T& instance) in C:\orchard\src\Orchard\Mvc\OrchardControllerFactory.cs:26
   Orchard.Mvc.OrchardControllerFactory.GetControllerInstance(RequestContext requestContext, Type controllerType) in C:\orchard\src\Orchard\Mvc\OrchardControllerFactory.cs:71
   System.Web.Mvc.DefaultControllerFactory.CreateController(RequestContext requestContext, String controllerName) +93
   System.Web.Mvc.MvcHandler.ProcessRequestInit(HttpContextBase httpContext, IController& controller, IControllerFactory& factory) +346
   System.Web.Mvc.<>c__DisplayClass6.<BeginProcessRequest>b__2() +71
   System.Web.Mvc.<>c__DisplayClassb`1.<ProcessInApplicationTrust>b__a() +19
   System.Web.Mvc.SecurityUtil.ProcessInApplicationTrust(Func`1 func) +161
   Orchard.Mvc.Routes.HttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData) in C:\orchard\src\Orchard\Mvc\Routes\ShellRoute.cs:143
   System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +405
   System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +375



Version Information: Microsoft .NET Framework Version:4.0.30319; ASP.NET Version:4.0.30319.237

This is my serivce code:

using System.Collections.Generic;
using System.Linq;
using Orchard;
using Orchard.Data;
using Orchard.ContentManagement;
using Donation.ViewModels;
using Donation.Models;
using Orchard.Security;


//  SERVICE:
//  Handles the DB operations

namespace Donation.Services
{
    public interface IMemberService : IDependency
    {
        void UpdateMemberForContentItem(ContentItem item, EditMemberViewModel model);
        IEnumerable<DonationRecord> GetDonations();
        IEnumerable<DonationRecord> GetMemberDonations(int id);
        void RemoveDonation(DonationRecord donation);
    }

    public class MemberService : IMemberService
    {
        private readonly IRepository<DonationRecord> _donationRepository;

        public MemberService(IRepository<DonationRecord> donationRepository)
        {
            _donationRepository = donationRepository;
        }

        
        public void UpdateMemberForContentItem(ContentItem item, EditMemberViewModel model)
        {
            var donationPart = item.As<MemberPart>();
            //DonationPart.UserId = model.UserId;
            donationPart.Lifetime = model.Lifetime;

            
            //donationPart. = _donationRepository.Get(d => d.Id == 1);

            //var userNames = ContentManager.Query<UserPart, UserPartRecord>().Where(u => userIds.Contains(u.Id)).List().Select(u => u.UserName);
        }
        

        /// <summary>
        /// ////////////////////////////////////////////////////
        /// </summary>
        /// <returns></returns>
        
        public IEnumerable<DonationRecord> GetDonations()
        {
            return _donationRepository.Table.ToList();
        }
        
        public IEnumerable<DonationRecord> GetMemberDonations(int id)
        {
            return this.GetDonations().Where(d => d.MemberPartRecord.Id == id);
        }

        public void RemoveDonation(DonationRecord donation) {

            //DonationRecord del = _donationRepository.Get(id);
            //_donationRepository.Delete(del);
            _donationRepository.Delete(donation);
        }

        public void RemoveDonation(IEnumerable<DonationRecord> votes)
        {
            foreach (var vote in votes)
                _donationRepository.Delete(vote);
        }
    }
}

Can anyone help us out? Thanks in anticipation, Cheers Dyr

Coordinator
Feb 14, 2012 at 5:06 AM

Why are you injecting the concrete class and not the interface?

Feb 14, 2012 at 6:39 AM

Sorry, could you rephrase the above so that a simpleton with very little programming knowledge, let alone orchard 'know how' may understand. If I'm doing something blatantly wrong, it's because I wouldn't know any better.  Thanks Dyr

Coordinator
Feb 14, 2012 at 6:42 AM

When you wrote: 

private readonly MemberService _memberService;

public DonationController(MemberService memberService){

Why didn't you use IMemberService instead?

Feb 14, 2012 at 10:34 AM

Ah, thanks bertrandleroy that would've been by accident.  I no longer receive that error, so i'm back to my original question; am I calling the remove action correctly?

@Html.ActionLink("Remove", "Remove", "Donation", new { Area = "Donation", donationId = don.Id }, null)

Cheesr Dyr

Coordinator
Feb 14, 2012 at 7:17 PM

It looks fine. Is it still not working? If so, what happens?

Feb 14, 2012 at 9:34 PM

A 404 error, so I'm assuming something is wrong with my routes?

using System.Collections.Generic;
using System.Web.Mvc;
using System.Web.Routing;
using Orchard.Mvc.Routes;

namespace Donation {
    public class Routes : IRouteProvider {
        public void GetRoutes(ICollection<RouteDescriptor> routes) {
            foreach (var routeDescriptor in GetRoutes())
                routes.Add(routeDescriptor);
        }

        public IEnumerable<RouteDescriptor> GetRoutes() {
            return new[] {
                new RouteDescriptor {
                    /*Priority = 5,*/
                    Route = new Route(
                        "Donation/Remove",
                        new RouteValueDictionary {
                            {"area", "Donation"},
                            {"controller", "Donation"},
                            {"action", "Remove"}
                        },
                        new RouteValueDictionary(),
                        new RouteValueDictionary {
                            {"area", "Donation"}
                        },
                        new MvcRouteHandler())
                }
            };
        }
    }
}

Coordinator
Feb 14, 2012 at 10:33 PM

I don't think so: ActionLink is generating the URL from the route table, so any url it generates should correspond to something in the table. What URL do you see when you do view source on the page with the action link?

Feb 14, 2012 at 11:54 PM

Ok, the page url is:

http://localhost/Orc/Admin/Users/Edit/14


The actionlink is as follows:

http://localhost/Orc/Donation/Remove?donationId=2


source:

<a href="/Orc/Donation/Remove?donationId=2">Remove</a>

 

Shouldn't it be something like: http://localhost/Orc/Admin/Users/Edit/14/Donation/Remove?donationId=2     ?

Cheers Dyr.

Coordinator
Feb 15, 2012 at 12:11 AM

mmh, no, why would it have that admin/users/edit/14 part? It's not a relative URL, it has a leading slash. No, this looks all normal. Did you try p[utting a breakpoint in the controller action?

Feb 15, 2012 at 12:21 AM

Yeah, it doesn't get called?

Coordinator
Feb 15, 2012 at 12:36 AM

Nothing in app_data\logs?

Feb 15, 2012 at 12:42 AM

It just removed [Httppost] and [ValidateAntiFOrgery] and it now gets called with this result:

Server Error in '/Orc' Application.

A route named 'orctest' could not be found in the route collection.
Parameter name: name

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.ArgumentException: A route named 'orctest' could not be found in the route collection.
Parameter name: name

Source Error:

Line 146:            public void EndProcessRequest(IAsyncResult result) {
Line 147:                try {
Line 148:                    _httpAsyncHandler.EndProcessRequest(result);
Line 149:                }
Line 150:                finally {


Source File: C:\orchard\src\Orchard\Mvc\Routes\ShellRoute.cs    Line: 148

Stack Trace:

[ArgumentException: A route named 'orctest' could not be found in the route collection.
Parameter name: name]
   System.Web.Routing.RouteCollection.GetVirtualPath(RequestContext requestContext, String name, RouteValueDictionary values) +3876168
   System.Web.Mvc.RouteCollectionExtensions.GetVirtualPathForArea(RouteCollection routes, RequestContext requestContext, String name, RouteValueDictionary values, Boolean& usingAreas) +94
   System.Web.Mvc.UrlHelper.GenerateUrl(String routeName, String actionName, String controllerName, RouteValueDictionary routeValues, RouteCollection routeCollection, RequestContext requestContext, Boolean includeImplicitMvcValues) +145
   System.Web.Mvc.UrlHelper.GenerateUrl(String routeName, String actionName, String controllerName, String protocol, String hostName, String fragment, RouteValueDictionary routeValues, RouteCollection routeCollection, RequestContext requestContext, Boolean includeImplicitMvcValues) +76
   System.Web.Mvc.UrlHelper.RouteUrl(String routeName) +167
   Donation.Controllers.DonationController.Remove(Int32 donationId) +325
   lambda_method(Closure , ControllerBase , Object[] ) +112
   System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters) +264
   System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters) +39
   System.Web.Mvc.<>c__DisplayClass15.<InvokeActionMethodWithFilters>b__12() +129
   System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func`1 continuation) +826410
   System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func`1 continuation) +826410
   System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func`1 continuation) +826410
   System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodWithFilters(ControllerContext controllerContext, IList`1 filters, ActionDescriptor actionDescriptor, IDictionary`2 parameters) +314
   System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName) +825632
   System.Web.Mvc.Controller.ExecuteCore() +159
   System.Web.Mvc.ControllerBase.Execute(RequestContext requestContext) +335
   System.Web.Mvc.<>c__DisplayClassb.<BeginProcessRequest>b__5() +62
   System.Web.Mvc.Async.<>c__DisplayClass1.<MakeVoidDelegate>b__0() +20
   System.Web.Mvc.<>c__DisplayClasse.<EndProcessRequest>b__d() +54
   Orchard.Mvc.Routes.HttpAsyncHandler.EndProcessRequest(IAsyncResult result) in C:\orchard\src\Orchard\Mvc\Routes\ShellRoute.cs:148
   System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +469
   System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +375



Version Information: Microsoft .NET Framework Version:4.0.30319; ASP.NET Version:4.0.30319.237

I am now checking logs, cheers Dyr

Coordinator
Feb 15, 2012 at 12:53 AM

Where does that "orctest" come from? I don't see it anywhere in the code you posted.

Feb 15, 2012 at 12:54 AM

Oops, my return still had irrelevant test location:

 return Redirect(Url.RouteUrl("orctest"));
but that still shouldn't have stopped the removal of the record?

Feb 15, 2012 at 1:49 AM

So sorry bertrandleroy, after a full solution compile [not sure if I altered anything...] it did indeed remove the record/s as intended. Sincere thanks for all your efforts in helping me with this!!! Very much appreciated, Cheers Dyr