How to override route in a plugin nopcommerce - plugins

I've a route like Admin/Vendor in my MVC application . Without changing this route I need to point this same route to another method say CustomAdmin/CustomVendor.
I tried attribute routing but no luck . Is there any way to do this. My current code is given below
Original Method:
public class AdminController
{
public ActionResult Vendor()
{
return View();
}
}
Custom Method:
public class CustomAdminController
{
[Route("Admin/Vendor")]
public ActionResult CustomVendor()
{
return View();
}
}

As you're developing a plugin. You have to add your custom route to the RouteProvider.
In default nopCommerce AdminController and Vendor doesn't exists, so I assume that you're trying to override vendor list method of admin.
Which looks like:
public partial class RouteProvider : IRouteProvider
{
public void RegisterRoutes(RouteCollection routes)
{
var route = routes.MapRoute("Plugin.GroupName.PluginName.CustomVendor",
"Admin/Vendor/List",
new { controller = "CustomAdminController", action = "CustomVendor", orderIds = UrlParameter.Optional, area = "Admin" },
new[] { "Nop.Plugin.GroupName.PluginName.Controllers" });
route.DataTokens.Add("area", "admin");
routes.Remove(route);
routes.Insert(0, route);
}
public int Priority
{
get
{
return 100; // route priority
}
}
}
Side Note: GroupName and PluginName should be your plugin group name and plugin name.
Hope this helps !

On your plugin which class implements the interface IRouteProvider, you can easily override the route there.
Likewise I have a class named RouteProvider in my plugin, So I have Implemented the abstract function RegisterRoutes and simply it can be overrided by
routes.MapRoute("Plugin.Promotion.Combo.SaveGeneralSettings",
"Admin/Vendor",
new { controller = "CustomAdmin", action = "CustomVendor", },
new[] { "Nop.Plugin.Promotion.Combo.Controllers" }
);
Here Plugin.Promotion.Combo must be replaced by your plugin directory.And using SaveGeneralSettings or any things you want to use that will be your route url

Related

.Net core controller tempdata add/remove

Implementing ExceptionFilterAttribute OnException method and need to redirect
The old implementation (.Net 48) was
exceptionContext.Controller.TempData.Remove("");
exceptionContext.Controller.TempData.Add("");//exception message is added
exceptionContext.Controller.ControllerContext.HttpContext.Response.Redirect(url);
For the redirect I guess I can:
exceptionContext.HttpContext.Response.Redirect(url);//Is this correct?
Please suggest alternate for the remove and add?
In .net 6,there's no exceptionContext.Controller.TempData if you want to access TempData in your ExceptionFilter,you could try to inject the TempdataDictionaryFactory into the filter
For example, I tried as below:
public class MyExceptionFilter : ExceptionFilterAttribute
{
private readonly ITempDataDictionaryFactory _tempDataDictionaryFactory;
public MyExceptionFilter(ITempDataDictionaryFactory tempDataDictionaryFactory)
{
_tempDataDictionaryFactory = tempDataDictionaryFactory;
}
public override void OnException(ExceptionContext context)
{
var tempData = _tempDataDictionaryFactory.GetTempData(context.HttpContext);
tempData.Add("key", "value");
context.Result = new RedirectToActionResult("Error", "Home", null);
}
}
in Program.cs:
builder.Services.AddControllersWithViews(x=>x.Filters.Add(typeof(MyExceptionFilter)));
The Result:

How can I change a route value then redirect to that route?

I have a UserAccountController that takes routes like this "/{username}/{action}".
I'd like to create some functionality so that I can take a user to an account-specific page without knowing their username up front. I'd like to be able to use the URL "/your/{action}" which would catch the fact that "your" was sent as their username, get their real username (because they are logged in), and redirect them to "/their-actual-username/{action}".
I could do this in each of the controller actions, but I'd rather have it happen some place earlier that would do this for all of the controller actions. I attempted to do this in the Controller's Initialize method by changing the RouteData.Values["username"] to the real username then attempting to Response.RedirectToRoute(RouteData); Response.End() but that always took me to the wrong place (some completely wrong route).
Updated:
Thanks to BuildStarted for leading me to this answer:
public class UserAccountController : Controller
{
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
base.OnActionExecuting(filterContext);
if ((string) filterContext.RouteData.Values["username"] != "your")
return;
var routeValues = new RouteValueDictionary(filterContext.RouteData.Values);
routeValues["username"] = UserSession.Current.User.Username;
filterContext.Result = new RedirectToRouteResult(routeValues);
}
}
You can use the FilterAttribute with IActionFilter to accomplish what you want.
public class UserFilterAttribute : FilterAttribute, IActionFilter {
public void OnActionExecuted(ActionExecutedContext filterContext) {
}
public void OnActionExecuting(ActionExecutingContext filterContext) {
var username = filterContext.RouteData.Values["username"];
var realUserName = ""; //load from database
filterContext.Result = new RedirectToRouteResult(new System.Web.Routing.RouteValueDictionary(new { controller = "Users", action = "Index", username = realUserName }));
}
}
Then on your ActionResult in your controller you could apply [UserFilter] to the action.
[UserFilter]
public ActionResult UnknownUserHandler() {
return View();
}
This should get you the results you're looking for. Any questions please post :)

Why do ASP.NET MVC3 Areas and Razor Views produce this error?

The view at '~/Areas/SomeArea/Views/List/Index.cshtml' must derive from ViewPage, ViewPage, ViewUserControl, or ViewUserControl.
The project structure is pretty much default. There is one area called SomeArea. It has a single controller called List. It does nothing except:
public ActionResult Index()
{
return View("~/Areas/SomeArea/Views/List/Index.cshtml");
}
The view looks like:
#inherits System.Web.Mvc.WebViewPage<dynamic>
#{
View.Title = "Index";
LayoutPage = "~/Views/Shared/_Layout.cshtml";
}
<h2>Index</h2>
I have tried emptying the entire file part by part and nothing seems to help. If I create a controller and view outside the area it works just fine. Is it possible the default razor view engine doesn't support areas at this time?
Edit: The areas are registered.
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Random", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
}
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"SomeArea_default",
"SomeArea/{controller}/{action}/{id}",
new { controller = "List", action = "Index", id = UrlParameter.Optional }
);
}
An answer from the ASP.NET Forums:
http://forums.asp.net/t/1593209.aspx
This fixed the problem. Thanks to the replier!
Getting the error "The view at '~/Views/Page/home.aspx' must derive from ViewPage, ViewPage<TViewData>, ViewUserControl, or ViewUserControl<TViewData>" Similar question, might help you. Also, did you register your areas in the global.asax?

Stripes : RedirectResolution; How can I redirect to specific action event?

I have an action bean in my stripes application. The default handler/method will display a list of data, a list of all my MarketResearch objects
On my JSP, I can click on one to view its details, this takes me to a different JSP with a pre-populated form based on the particular MarketResearch object that you selected.
I have another method on my action bean which is mapped to the save submit button, this takes in what is on the amended form, and persists it. After this has taken place, I want it to redirect back to the form, rather than to the listing (default handler) action, is this possible?
My action is as follows :
public class MarketResearchAction extends BaseAction
{
#SpringBean
ClientService clientService;
private static final String VIEW = "/jsp/marketResearch.jsp";
private Client client;
private Client clientBeforeChanges;
public Client getClient()
{
return client;
}
public void setClient(Client client)
{
this.client = client;
}
#DefaultHandler
public Resolution viewAll()
{
return new ForwardResolution(VIEW);
}
public Resolution viewClientMarketResearch()
{
if (client.getSector().equals("Education"))
{
return new ForwardResolution("/jsp/marketResearchEducation.jsp");
} else if (client.getSector().equals("Local Government"))
{
return new ForwardResolution("/jsp/marketResearchLocalGovernment.jsp");
} else if (client.getSector().equals("Housing Association"))
{
return new ForwardResolution("/jsp/marketResearchHousing.jsp");
}
return new ForwardResolution("/jsp/viewClientMarketResearch.jsp");
}
public Resolution save()
{
clientBeforeChanges = clientService.getClientById(client.getId());
clientService.persistClient(client);
getContext().getMessages().add(new SimpleMessage("{0} updated", client.getName()));
return new RedirectResolution("/MarketResearch.action").flash(this);
}
public Client getClientBeforeChanges()
{
return clientBeforeChanges;
}
public void setClientBeforeChanges(Client clientBeforeChanges)
{
this.clientBeforeChanges = clientBeforeChanges;
}
public ClientService getClientService()
{
return clientService;
}
public void setClientService(ClientService clientService)
{
this.clientService = clientService;
}
}
Is it possible? Or am I approaching the situation from a bad angle and should re-factor?
Thanks
Yes. You could return a RedirectResolution to the form jsp. If you're having difficulty with the parameters, if you have them in the save() method, you could do like so:
return new RedirectResolution("/theJsp.jsp")
.addParameter("one", one)
.addParameter("two", two)
.addParameter("three", three)
.flash(this);
If you don't have the params that were passed to the form, you'll have to keep them going somehow. You could pass the MarketResearch object through the form so you'd have it there.
<stripes:hidden name="marketResearch" value="${ActionBean.marketResearch}"/>
And add the requisite instance variable/getter/setter on your MarketResearchActionBean.

StructureMap InstanceInterceptor not being called

I want to intercept the creation of an instance in SM and I'm trying the following but it's not calling the InstanceInterceptor implementation, does anyone know why?
ForRequestedType<IPublishResources>()
.TheDefault
.Is
.OfConcreteType<PublisherService>()
.InterceptWith(new PublisherServiceInterceptor());
The test code uses the ObjectFactory to create instances, and is shown below:
// Given we have a configure object factory in StructureMap...
ObjectFactory.Configure(x => x.AddRegistry(new StructureMapServiceRegistry()));
// When we request a publisher service...
var publisher = ObjectFactory.GetInstance<IPublishResources>();
Cheers
AWC
I could not reproduce your problem in release 2.5.4. Here is my code.
public interface IPublishResources {}
class PublishResources : IPublishResources {}
public class LoggingInterceptor : InstanceInterceptor
{
//this interceptor is a silly example of one
public object Process(object target, IContext context)
{
Console.WriteLine("Interceptor Called");
return context.GetInstance<PublishResources>();
}
}
public class MyRegistry : Registry
{
public MyRegistry()
{
For<IPublishResources>()
.Use<PublishResources>()
.InterceptWith(new LoggingInterceptor());
}
}
[TestFixture]
public class Structuremap_interception_configuraiton
{
[Test]
public void connecting_implementations()
{
var container = new Container(cfg =>
{
cfg.AddRegistry<MyRegistry>();
});
container.GetInstance<IPublishResources>();
}
}
A question. Do you really need to use an Interceptor here? If you only need to define a factory you can do somethign like this.
public interface IPublishResourcesFactory
{
IPublishResources Create();
}
public class MyRegistry : Registry
{
public MyRegistry()
{
For<IPublishResources>().Use(c =>
{
return c.GetInstance<IPublishResourcesFactory>().Create();
});
//or
For<IPublishResources>().Use(c =>
{
//other object building code.
return new PublishResources();
});
}
}