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();
}
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 got a problem when debugging my MVC program and I want to acces to my db called "UserActivity".
on the browser, it saying that "The localhost page isn’t working
localhost redirected you too many times."
but without showing the specific error location.
here is my UserActivtyController, GET /UserActivity/Index code:
public class UserActivityController : BaseController
{
//GET /UserActivity/Index
public ActionResult Index(string returnUrl, int page = 1, string sort = "Id", string sortDir = "ASC", string filter = null)
{
String query = #"
SELECT Id
,CreatedBy
,CreatedOn
,ModifiedBy
,ModifiedOn
,ContactId
,EntityName
,EntityId
,ActivityType
,ActivityStatus
,DueDate
,ActualEndDate
,MasqueradeOn
,MasqueradeBy
FROM UserActivity
-- ORDER BY CreatedOn DESC
-- OFFSET (#PageNumber -1) * 30 ROWS
-- FETCH NEXT 30 ROWS ONLY
";
//string countQuery = #""
List<UserActivityModels> userActivity = null;
using (IDbConnection db = new MySqlConnection(ConfigurationManager.ConnectionStrings["CRMPORTALSQLCONN"].ConnectionString))
{
userActivity = (List<UserActivityModels>)db.Query<UserActivityModels>(query, new
{
#PageNumber = page,
});
/*ViewData["TotalCount"] = (int)db.ExecuteScalar(countQuery, new
{
#PageNumber = page,
#Id = string.IsNullOrEmpty(filter) ? null : filter
});
*/
ViewData["PageSize"] = 30;
ViewData["Filter"] = filter;
}
if (userActivity != null)
{
return RedirectToAction(returnUrl);
}
return View(userActivity);
}
}
Really appreciate if there anyone who know something about this problem. Thanks
if (userActivity != null)
{
return RedirectToAction(returnUrl);
}
If the returnUrl points to the same action ("UserActivity/Index") it will create infinite redirect loop. If you want to redirect request to different action make sure you pass correct name.
You have a loop back situation. This is similar to endless while loop. To fix it change your code redirection implementation to redirect to an action method. Notice how I have changed the implementation below. This will fix the issue "localhost redirected you too many times". You can improve on it to support passing in parameters, etc suitable for your situation. Also take a look at RedirectToAction with support for additional parameters, if you want to pass parameters to the action method, this link will be useful.
public class UserActivityController : BaseController
{
//GET /UserActivity/Index
public ActionResult Index(int page = 1, string sort = "Id", string sortDir = "ASC", string filter = null)
{
// Your other implementation here. I have removed it for brevity.
if (userActivity != null)
{
return RedirectToAction("Index");
}
return View(userActivity);
}
public ActionResult Index()
{
return View();
}
}
I don't know what is the value of redirectUrl but I suppose it to be null. I also suppose that your userActivity is not null. So return RedirectToAction(returnUrl); gets called.
When you call RedirectToAction(null) you actually redirect to the same action and everything repeats again.
I also am wondering why would you need to return View(userActivity); when your userActivity is null. I suppose you have a logical error.
I created partial view and I call it like this:
#{Html.RenderAction("_SearchPartial", "Search", new { RenderVillaOption=true,RenderHotelOption=true,Frame=true,RenderAccommodationOption=true,RenderRentACarOption=true});}
I pass some values because I want them to be seen near the declaration od partial view and I controller I can get this values which is fine.
Than I post to some action inside SearchController. I would like to get this "Options" (route values I specified inside partial view declaration. How to achive that?
This is action method:
public string SearchAndRedirect([FromBody] SearchAPIModel searchModel)
{
var redirectUrl = "";
var c = ControllerContext;
switch (searchModel.ProductType)
Get them as parameters inside your ActionMethod:
public ActionResult Search(bool RenderVillaOption, bool RenderHotelOption, bool Framem ... )
{
}
As an alternative to #vortex answer, considering your comment you can use Request.Params:
public ActionResult Search(...)
{
var renderVillaOption = Request.Params["RenderVillaOption"];
}
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)
I have the following:
request url: 'endpoint/1,2,3?q=foo'
action to which the request is bound:
public object Bar([ModelBinder] List< T > ids, [FromUri] string q)
I want to map the "1,2,3" fragment to the "ids" parameter, so I created a ModelBinderProvider according to this link, which should call the proper model binder.
public class MyModelBinderProvider: ModelBinderProvider
{
public override IModelBinder GetBinder(HttpConfiguration configuration, Type modelType)
{
IModelBinder modelBinder = null;
if (modelType.IsGenericType && (modelType.GetGenericTypeDefinition() == typeof(List<>)))
{
modelBinder = new ListModelBinder();
}
return modelBinder;
}
}
I registered the provider in Global.asax like this:
GlobalConfiguration.Configuration.Services.Insert(typeof(ModelBinderProvider), 0, new MyModelBinderProvider());
The reason: I created this provider because I want, no matter what T is ('1,2,3' or 'one,two,three'), the bind to work.
The problem:
Let' say T is 'int'; everytime a request is sent, the 'modelType' paramater is always 'int' and not what I expect - 'List< int >', so the request is not properly handled.
The weird thing: Doing something like this works but T is specialized and therefor not what I want:
var simpleProvider = new SimpleModelBinderProvider(typeof(List<int>), new ListModelBinder());
GlobalConfiguration.Configuration.Services.Insert(typeof(ModelBinderProvider), 0, simpleProvider);
I cannot see what I'm doing wrong, why is the 'modelType' parameter not the expected value?
It is a very old question but I had an similar issue here with a legacy code.
Commas are reserved and it should be avoided although they work in some cases but if you really want to use them...
I think that is more a route issue than a model binder once the "1,2,3" is path part of the url. Assuming this I wrote a small RouteHandler that does the trick (please forgive the very simple "word to integer" translator).
The CsvRouteHandler gets the id array from URL and put it on RouteData as an array of integers. If the original array has words such as one, two or three it translates each value to int.
MvcRouteHandler
protected override IHttpHandler GetHttpHandler(System.Web.Routing.RequestContext requestContext)
{
var idArrayParameter = requestContext.RouteData.Values["idArray"] != null ? requestContext.RouteData.Values["idArray"].ToString() : null;
if (string.IsNullOrEmpty(idArrayParameter))
{
return base.GetHttpHandler(requestContext);
}
requestContext.RouteData.Values.Remove("idArray"); // remove the old array from routedata
// Note: it is horrible and bugged but and you probably have your own translation method :)
string[] idArray = idArrayParameter.Split(',');
int[] ids = new int[idArray.Length];
for(int i = 0; i < idArray.Length; i++)
{
if (!int.TryParse(idArray[i], out ids[i]))
{
switch (idArray[i])
{
case "one":
ids[i] = 1;
break;
case "two":
ids[i] = 2;
break;
case "three":
ids[i] = 3;
break;
}
}
}
requestContext.RouteData.Values.Add("Id", ids);
return base.GetHttpHandler(requestContext);
}
}
Route configuration:
routes.Add(
name: "Id Array Route",
item: new Route(
url: "endpoint/{idArray}",
defaults: new RouteValueDictionary(new { controller = "Test", action = "Index" }),
routeHandler: new CsvRouteHandler())
);