I'm trying to create this route:
http://localhost:28790/Admin/Reporting/Reporting?reportName=MyReportName
In order to access to this Controller:
public ActionResult Reporting(string reportName){...}
For this, i've added this routing in the area:
context.MapRoute(
"Admin_Reporting",
"Admin/Reporting/Reporting/{reportName}",
new
{
reportName = UrlParameter.Optional
}
);
And I've tested this ActionLink
#Html.ActionLink(My Link, "Reporting", "Reporting", new { area = "Admin", reportName = "reportingName" })
But indeed the result is not what I expect to have:
http://localhost:28790/Admin/Reporting/Reporting?Length=9
What can I do in order to have the right URL (first URL of the post) instread of this wrong URL (latest URL of the post) ?
Thanks in advance for your help
You using the wrong overload of #Html.ActionLink(). You need to use this overload when you specify null for the html attributes (the last parameter)
#Html.ActionLink("My Link", "Reporting", "Reporting", new { area = "Admin", reportName = "reportingName" }, null)
Related
I want to allow forward slash into SENAME of my nop project. How can i do this using customisation?
for example,
I want product url like "/product/htc-one-m8-android-l-50-lollipop" instead of "/htc-one-m8-android-l-50-lollipop"
I want category url like "/category/desktops" instead of "/desktops"
I am using nopcommerce 4.3 version.
sample code
endpointRouteBuilder.MapDynamicControllerRoute<SlugRouteTransformer>("SeName}");
I am not getting call into this TransformAsync method. i want to get call here when i add "/product/sename" into url
public override ValueTask<RouteValueDictionary> TransformAsync(HttpContext httpContext, RouteValueDictionary values)
{
}
You can register routes for Product/ and Category/ path in GenericUrlRouteProvider like:
endpointRouteBuilder.MapDynamicControllerRoute<SlugRouteTransformer>("Product/{SeName}");
endpointRouteBuilder.MapDynamicControllerRoute<SlugRouteTransformer>("Category/{SeName}");
If you want your existing links to be displayed correctly your also want to update default Product and Category routes and your register routes method should look like:
public void RegisterRoutes(IEndpointRouteBuilder endpointRouteBuilder)
{
var pattern = "{SeName}";
var productPattern = "Product/{SeName}";
var catgoryPattern = "Category/{SeName}";
if (DataSettingsManager.DatabaseIsInstalled)
{
var localizationSettings = endpointRouteBuilder.ServiceProvider.GetRequiredService<LocalizationSettings>();
if (localizationSettings.SeoFriendlyUrlsForLanguagesEnabled)
{
var langservice = endpointRouteBuilder.ServiceProvider.GetRequiredService<ILanguageService>();
var languages = langservice.GetAllLanguages().ToList();
pattern = "{language:lang=" + languages.FirstOrDefault().UniqueSeoCode + "}/{SeName}";
productPattern = "{language:lang=" + languages.FirstOrDefault().UniqueSeoCode + "}/{SeName}";
catgoryPattern = "{language:lang=" + languages.FirstOrDefault().UniqueSeoCode + "}/{SeName}";
}
}
endpointRouteBuilder.MapDynamicControllerRoute<SlugRouteTransformer>(pattern);
endpointRouteBuilder.MapDynamicControllerRoute<SlugRouteTransformer>(productPattern);
endpointRouteBuilder.MapDynamicControllerRoute<SlugRouteTransformer>(catgoryPattern);
//and default one
endpointRouteBuilder.MapControllerRoute(
name: "Default",
pattern: "{controller=Home}/{action=Index}/{id?}");
//generic URLs
endpointRouteBuilder.MapControllerRoute(
name: "GenericUrl",
pattern: "{GenericSeName}",
new { controller = "Common", action = "GenericUrl" });
//define this routes to use in UI views (in case if you want to customize some of them later)
endpointRouteBuilder.MapControllerRoute("Product", productPattern,
new { controller = "Product", action = "ProductDetails" });
endpointRouteBuilder.MapControllerRoute("Category", catgoryPattern,
new { controller = "Catalog", action = "Category" });
endpointRouteBuilder.MapControllerRoute("Manufacturer", pattern,
new { controller = "Catalog", action = "Manufacturer" });
endpointRouteBuilder.MapControllerRoute("Vendor", pattern,
new { controller = "Catalog", action = "Vendor" });
endpointRouteBuilder.MapControllerRoute("NewsItem", pattern,
new { controller = "News", action = "NewsItem" });
endpointRouteBuilder.MapControllerRoute("BlogPost", pattern,
new { controller = "Blog", action = "BlogPost" });
endpointRouteBuilder.MapControllerRoute("Topic", pattern,
new { controller = "Topic", action = "TopicDetails" });
//product tags
endpointRouteBuilder.MapControllerRoute("ProductsByTag", pattern,
new { controller = "Catalog", action = "ProductsByTag" });
}
Update:
In order to allow / in product name, there are multiple changes you need to make.
Allow / in sename, to do that UrlRecordService has GetSeName method and in okChars variable you want to add / as one of the valid characters.
Fix your call related to dynamic routes. You have { missing in your code. It should be:
endpointRouteBuilder.MapDynamicControllerRoute<SlugRouteTransformer>("{SeName}");
Update SlugRouteTransformer's TransformAsync method to unescape URL before searching for matching Url records using:
var urlRecord = _urlRecordService.GetBySlug(Uri.UnescapeDataString(slug));
I believe that is all and after that you should be able to allow / in your entity name. Be aware that this might break existing pages and links might not work perfectly all the time. Also, if you look closely, your product/category url will have %2F in the URL, if you want to change that you will have to unesacpe all the links before rendering, something like:
#Model.Name BUT IT WILL BREAK A LOT OF THINGS!
I have this page (item) in my Sitecore website that is viewed from a Facebook page tab. It's a rather simple page, but I have an issue with Sitecore giving me the wrong language on first load, then subsequent loads are ok.
This item runs through this controller:
//
// GET: /Portfolio/
public override ActionResult Index()
{
var appId = "*****";
var appSecret = "*****";
// Defaults to en
var requestLanguage = "en";
// Get language from FB
if (Request.Form["signed_request"] != null)
{
if (Request.Url.Host.ToLower().Contains("local")) {
appId = "*****";
appSecret = "*****";
}
var fbUser = new Facebook.FacebookClient
{
AppId = appId,
AppSecret = appSecret
};
var parsedSignedRequest = JObject.Parse(fbUser.ParseSignedRequest(Request.Form["signed_request"]).ToString());
if (parsedSignedRequest != null)
{
requestLanguage = parsedSignedRequest["user"]["locale"].ToString().StartsWith("fr") ? "fr-CA" : "en";
} // Else: Request can't be parsed, something is wrong
} // Else: Probably not in FB
// ?l=***** can bypass language setting
if (!string.IsNullOrWhiteSpace(Request.QueryString["l"]))
{
requestLanguage = Request.QueryString["l"];
}
Context.Language = Language.Parse(requestLanguage);
// Views will need this
ViewBag.requestLanguage = requestLanguage;
ViewBag.appId = appId;
return base.Index();
}
When I debug this, it works perfectly. I'm setting Sitecore's Context.Language to that of what the Facebook user uses (I have french and english content).
Now onto views, I have this master layout that basically just (other than boring html markup) places the placeholder:
#Html.Sitecore().Placeholder("fb-body")
Finally, my view rendering looks like this:
#using Sitecore.Globalization
#using Sitecore.Data.Items
#model RenderingModel
#{
// I checked this and the context language here is always correctly set, even on first load (controller did that)
// Sitecore.Context.Language = Language.Parse(ViewBag.requestLanguage);
var all = "All";
var back = "Back";
var projetTitle = "the project";
var servicesTitle = "services";
// Since my language is correctly set, this works fine
if (Language.Current.Name.ToLowerInvariant().Contains("fr"))
{
all = "Tous les projets";
back = "Retour";
projetTitle = "le projet";
servicesTitle = "services";
}
var portfolio = Model.Item.Parent.Children.FirstOrDefault(x => x.TemplateName == "Portfolio");
var wrongLanguage = portfolio.Language;
var wrongLanguage2 = Model.Item.Language;
}
Here when I pull my portfolio node, it's in the wrong language. If I look in Model.Item.Language, I also get the wrong language.
What am I missing here, is there something else I need to tell Sitecore so that he understands my language? This also sort of looks like a caching issue... Where do I look to solve this?
Thanks!
I am not sure what base controller you have set up, but it seems you make use of the PageContext.Current.PageView either by returning it yourself or inheriting from the SitecoreController. I bumped into some issues trying to reproduce the problem so I ended up with this:
public class TestController : Controller
{
public ActionResult Index()
{
Sitecore.Context.SetLanguage(Language.Parse("nl-NL"), true);
var view = (PageContext.Current.PageView) as RenderingView;
var renderer = view.Rendering.Renderer as ViewRenderer;
renderer.ViewPath = "/Views/Test/Index.cshtml";
return View(view);
}
}
And in my view I render:
#model Sitecore.Mvc.Presentation.RenderingModel
Context language is: #Sitecore.Context.Language<br/>
Model language is: #Model.Item.Language
First time result:
Context language is: nl-NL
Model language is: en
Second time result:
Context language is: nl-NL
Model language is: nl-NL
The problem is that the language resolver first sets the language to the default (being 'en') and when it gets into your controller action it has already fetched the Item with 'en'. So your language adjustment comes in too late. The second time it is loaded in correct language because the adjusted language was persisted in a cookie.
A proper place to set the language would be the LanguageResolver. You can override/extend the LanguageResolver and replace it in the httpRequestBegin pipeline. That way you will also prevent localized content being cached with the default language in the cachekey.
I have seen a couple related questions to this, but I cannot seem to solve my exact instance. I have a url such as http://127.0.0.1/UTS/Unit/J0000001. That is, my controller is UTS, my action is Unit and there is an optional parameter c_number.
I have my route configured as follows:
routes.MapRoute(
name: "Unit",
url: "{controller}/{action}/{c_number}",
defaults: new { controller = "UTS", action = "Unit", c_number = "" }
);
Then, my action in my controller as:
public ActionResult Unit(string c_number)
{
UnitViewModel uvm = new UnitViewModel();
uvm.unit = pacificRepo.Units.FirstOrDefault(g => g.c_number == c_number);
uvm.geoLocation = pacificRepo.GeoLocations.FirstOrDefault(g => g.geo_location.Latitude == uvm.unit.geo_location.Latitude && g.geo_location.Longitude == uvm.unit.geo_location.Longitude);
return View(uvm);
}
Whenever I go to the example URL I gave above, c_number comes up as null. It should be J0000001. Does anyone see something blatantly obvious that I'm missing?
Since you define it in your Route you don't need to add parameter for your c_number.You can get your value from RouteData dictionary.That c_number parameter has value only if you pass it as QueryString like http://someurl.com/UTS/Unit?c_number="J0000001"
public ActionResult Unit()
{
var cNumber = RouteData.Values["c_number"].ToString();
}
Hi I have a WebGrid with two columns:
1-Name
2-Action binded to another controller action. On click i will
re-direct to that action, parameter should be a List of List<Test>
items.
Output:
Request goes to Controller but parameter is empty colelction, am i missing anything.
View:
#model IEnumerable<Test>
<div id="testGrid">
#{
var grid = new WebGrid(ajaxUpdateContainerId: "testGrid", canSort: true);
grid.Bind(Model);
#MvcHtmlString.Create(
#grid.GetHtml(
columns: grid.Columns
(
grid.Column(Html.DisplayNameFor(model => model.Name).ToHtmlString(),
header: Html.DisplayNameFor(model => model.Name).ToHtmlString()),
grid.Column("Action", header: "Action", format: #<a href="#Url.Action("LoadTest", "NewController",
new
{
ingredients = Model.Select(t=>t.Id==#item.Id).ToList()
}
)" class="edit-btn"></a>)
)
).ToString()
)
}
</div>
Controller code
List coming empty.
public ActionResult LoadTest(List<Test> testItems)
{
//...test code.
}
Your Url.Action is creating a different variable than what your controller is expecting:
Either change your action from ingredients, to testItems:
grid.Column("Action", header: "Action", format: #<a href="#Url.Action("LoadTest", "NewController",
new
{
testItems = Model.Select(t=>t.Id==#item.Id).ToList()
}
or change your controller to expect a parameter called ingredients:
public ActionResult LoadTest(List<Test> ingredients )
{
//...test code.
}
Also, did you update your Global.asax to expect a route of this type? This example is assuming you keep the name testItems as your parameter.
routes.MapRoute(
"Test route", // Route name
"NewController/{action}/{testItems}", // URL with parameters
new { controller = "NewController", action = "LoadTest" } // Parameter defaults
);
Hi I have registered route as below :-
routes.MapLocalizedRoute("Category",
"{SeName}-c{categoryId}",
new { controller = "Catalog", action = "Category", SeName = UrlParameter.Optional },
new { categoryId = #"\d+", SeName = #"([-\w+]+(/[-\w+]+)*)+" },
new[] { "Nop.Web.Controllers" });
routes.MapLocalizedRoute("CategoryWithManufacture",
"{SeName}-d{categoryId}/{ManufactureName}/{Color}",
new { controller = "Catalog", action = "Category", SeName = UrlParameter.Optional, Color = UrlParameter.Optional },
new { categoryId = #"\d+", SeName = #"([-\w+]+(/[-\w+]+)*)+", ManufactureName = #"([-\w+]+(/[-\w+]+)*)+", Color = #"([-\w+]+(/[-\w+]+)*)+" },
new[] { "Nop.Web.Controllers" });
We generate these like below :-
href="#Url.RouteUrl("CategoryWithManufacture", new { categoryId = currentCategoryId, SeName = seName, ManufactureName = manufacturerFilterItem.Name, Color = color })"
href="#Url.RouteUrl("Category", new { categoryId = currentCategoryId, SeName = seName})"
There is a way to assign value directly to second parameter "Color" without assign value to "ManufactureName". means :- (Using CategoryWithManufacture Route)
/gloves-d18/red (second parameter)
/gloves-d18/hp/red (first and second both)
I have tried these by making manufactureName & color both optional but when we assign value to first parameter not second it , it work . But we assign value to second parameter not first ,then it is not work .
Please suggest me usable link or sample code.
Only the last parameter can be optional in a route definition. Given the following url /gloves-d18/red the route engine cannot possible know that red refers here to {Color} and not {ManufactureName}. The only to make this work is to write some constraint for those 2 parts. Right now they both have the exactly same regular expression constraint.