HttpContext AbsolutePath goes to wrong URL for aliased pages - C# - url

On my website each page has links that are created in the codebehind, where the links are the current URL with one query parameter changed. To do this, I've been using this method (this specific example is for the pagination):
var queryValues = HttpUtility.ParseQueryString(HttpContext.Current.Request.QueryString.ToString());
queryValues.Set("page", num);
string url = HttpContext.Current.Request.Url.AbsolutePath;
string updatedQueryString = "?" + queryValues.ToString();
string newUrl = url + updatedQueryString;
return newUrl;
This worked on my local version fine. However, when I created each page in Ektron and added a manual alias, the URLs generated still went to the file location in the solution. For example, my original page was /WebAssets/Templates/EventListView.aspx. I created the page in Ektron as /Alumni/Events/List. I can go to /Alumni/Events/List, but then when I click on a page button the page that loads is /WebAssets/Templates/EventListView.aspx?page=2 instead of /Alumni/Events/List/?page=2

I found one solution:
var rawUrl = HttpContext.Current.Request.RawUrl;
var url = rawUrl.Split('?')[0];
string newUrl = url + updatedQueryString;

Use the QuickLink property of the primary contentblock for /Alumni/Events/List, this will be the alias use want to use for your page links or for redirects to the same page. This is probably ContentData.QuickLink if you're already loading the ContentData at some point in the code.
Notes:
Aliasing may remove your "page" querystring parameter by default, to resolve this issue, edit your alias in the Workarea to have a "Query String Action" of "Append".
Make sure you preprend a "/" to the QuickLink value (if it's not absolute and not prepended already) if using it on the frontend, otherwise your links will bring you to something like /Alumni/Events/List/Alumni/Events/List?page=2, which is no good.

Related

How to resolve links to content items inside a rich text ? (Kontent.ai - ASP.NET framework)

So I followed the Kontent doc from the github which allows to retrieve content from a link (https://github.com/Kentico/kontent-delivery-sdk-net/wiki/Resolving-links-to-content-items)
First I implement a resolver to redirect when we click on the link like this :
public class CustomContentLinkUrlResolver : IContentLinkUrlResolver
{
public string ResolveBrokenLinkUrl()
{
return "/404";
}
public string ResolveLinkUrl(ContentLink link)
{
switch(link.ContentTypeCodename)
{
case "author":
return $"/author/{link.UrlSlug}";
default:
return $"/not_found";
}
}
}
Then I register my resolver within a IDeliveryClient
client = DeliveryClientBuilder
.WithProjectId(myid)
.WithContentLinkUrlResolver(new CustomContentLinkUrlResolver())
.Build();
At this moment if i click on the link it will redirect to /author/linkName with an error on the page what I think is normal
I don't get the last part of the doc (how just by doing a getString on the contentItem the link will work ?) so I would like to know how to display the content on the redirect page
I don't know if i was clear enough and sorry for my english
Here is the error thrown on the redirect page
Description: HTTP 404. The resource you are looking for (or one of its dependencies) could have been removed, had its name changed, or is temporarily unavailable. Please review the following URL and make sure that it is spelled correctly.
The last part of the wiki article refers to something that you already have:
At this moment if i click on the link
If you have a link that you can click on, then you have done what that part of the article describes.
What you need is to resolve the request. If you are getting a 404 that you expect, then you know that you need to add a route to your application to handle the request. In the handler (a controller, a component, etc.) extract the urlSlug from the route and use it with a IDeliveryClient to retrieve the item and then render the content. You will need to filter the GetItems call with something like new EqualsFilter("elements.urlSlug", urlSlug).

Owin/NancyFx Trailing Slash on Root Path

I have an Owin/NancyFx single-page application using AngularJs and UI Router.
Its hosted in IIS7 and for the most part everything is working. However there is one annoying issue with the root path that I can't seem to solve.
I would like a trailing slash on the root path, something like:
http://myserver.internaldomain.com/myapp/
This way when UI Router goes to handle the hashbang routing, all urls will look like:
http://myserver.internaldomain.com/myapp/#/mySpaRoute
However, I can't seem to get a trailing slash to append, so instead my URL looks like:
http://myserver.internaldomain.com/myapp#/mySpaRoute
I have tried to create an Owin middleware the looks at the URL and redirects if there's a missing / at the end. This works for all routes that are handled by the WebApi but not NancyFx. That seems reasonable since NancyFx takes over routing early to handle rendering its views.
Next I tried a NancyFx BeforeRequest pipeline lambda to do the same thing, interrogate the URL and append a / as needed. This however resulted in a redirect loop. The request would come in to the pipeline as: http://example.com/app, and then redirect to: http://example.com/app/, however at the next pipeline execution, the trailing / would be stripped and the pipeline handler would redirect again -- this is where the loop occured.
So I guess simply, how do I make NancyFx add a trailing / to the end of my routes?
Update:
Went to lunch, talked to the duck a bit, updated all the assemblies, then decided that its just the root get path that I really need to append the / to make hashbang routing look decent:
public class HomeModule : NancyModule
{
// note this works fine when running from localhost, but when running
// as an application in IIS, a redirect loop occurs
public HomeModule()
{
Get["/"] = _ =>
{
var requestUri = new Uri(Request.Url);
if (!requestUri.AbsoluteUri.EndsWith("/"))
{
var targetUri = requestUri.ToString() + "/";
return Response.AsRedirect(targetUri);
}
const string view = "views/home.cshtml";
var model = new { Title = Constants.ApplicationTitle };
return View[view, model];
}
}
}
Annnnnnd Redirect loop.
Ultimately this appears to have been caused by the Uri class. The Uri class does a very good job of removing trailing slashes in many cases. This means that I was, essentially, fixing any "malformed" urls by creating a new Uri out of them. Then I was breaking these nice Uri's by appending a / to them. On redirect the newly cast Uri would remove my extraneous /, then fail the if statement and the process would begin again, hence by redirect loop.
To fix the issue, I instead used the System.Web.HttpContextBase property provided in the owin environment context and checked the Request.Url property which seems to be the original requested Url with little or no post-processing.
These changes were made in my EnforceTrailingSlashMiddleware that I had written earlier. Here is the invoke method:
public override async Task Invoke(IOwinContext context)
{
var httpContext = context.Environment["System.Web.HttpContextBase"] as System.Web.HttpContextBase;
if (httpContext != null && httpContext.Request != null && httpContext.Request.Url != null)
{
var path = httpContext.Request.Url.ToString();
/*
formatter is a class ("SlashFormatter") with two methods:
"ShouldAppendSlash" which takes a path string and returns a boolean
(whether or not a slash should be appended)
"AppendSlash" which takes a string, safely appends a slash and
then returns the modified string.
*/
if (formatter.ShouldAppendSlash(path))
{
var url = formatter.AppendSlash(path);
context.Response.Redirect(url);
}
}
await Next.Invoke(context);
}

Reconstructing a Razor URL using referring URL and language selection

To implement language selection in an MVC Razor application, I use a leading path segment in the route mapping like www.mydomain.com/lang/controller/action/id?param= where lang is a 2 letter ISO country code like fr, de, it, en etc
I use the following route mapping (which works fine):
// Special localisation route mapping - expects specific language/culture code as first param
routes.MapRoute(
name: "Localisation",
url: "{lang}/{controller}/{action}/{id}",
defaults: new { lang = "en", controller = "Home", action = "Index", id = UrlParameter.Optional },
constraints: new { lang = #"[a-z]{2}|[a-z]{2}-[a-zA-Z]{2}" }
);
Previously I generated my language selection links in the master page, so that they were simply variations of the current URL (with only the first segment changed). Now I need to be able to create the links from within a partial view, that may be loaded dynamically via Ajax and the menu items (countries) are data driven.
That means I need to take the referring URL instead (the actual loaded page) and modify it to have a new language inserted, for each available language. The menu items are all database driven, so only contain the 2 letter language code and the display name.
Googling for "how to separate a URL into controller and action" I found an interesting link here: http://average-joe.info/url-to-route-data/
Based on that link, this is what I tried, but it blows up on a root URL like http://localhost:51176/ or with a full URL like http://localhost:51176/en/home/index. I would have expected it to return the defaults of home (controller) and index (action). Instead I get a Null reference exception.
string path = Request.UrlReferrer.ToString();
string queryString = ""; // Blank for now
System.Web.Routing.RouteData routeFromUrl = System.Web.Routing.RouteTable.Routes.GetRouteData(new HttpContextWrapper(new HttpContext(new HttpRequest(null, new UriBuilder(Request.Url.Scheme, Request.Url.Host, Request.Url.Port, path).ToString(), queryString), new HttpResponse(new System.IO.StringWriter()))));
// Blows up with Null exception as routeFromUrl is always null
string controller = (string)routeFromUrl.Values["controller"];
string action = (string)routeFromUrl.Values["action"];
string id = (string)routeFromUrl.Values["id"];
The idea being I can then generate links with href values like these using the referrers controller, action and parameters and therefore stay on the "same page" (except for the obvious language change):
http://localhost:51176/en/home/index
http://localhost:51176/de/home/index
http://localhost:51176/fr/home/index
What is wrong with the way I have used that piece of code (or does it just not work as I expected)?
Do'h... so simple.
Just needed to supply the path part of the URL only as it uses the current scheme, host & port applied to that path.
string path = Request.UrlReferrer.AbsolutePath;
Also note (valuable tip):
If you follow that example I linked, like I did, you need to adjust the following to use ToString() as they do not cast to string when empty:
string controller = routeFromUrl.Values["controller"].ToString();
string action = routeFromUrl.Values["action"].ToString();
string id = routeFromUrl.Values["id"].ToString();
This will give controller="home", action="index" and id="" as expected! Phew

ASP MVC Relative URL Path(not file)

I have a link to <a href='/ViewReport'> on my local host that works fine, but on the server the whole site is in a folder "serverfolder", so the link becomes http://somesite/serverfolder/ViewReport, which isn't a valid url. I have seen how to use ~ to access the root directory for files, but not how to do this with url paths. I want to use the same link for both local and remote deployment. How would I achieve this? Thank you!
Do this:
var urlHelper = new UrlHelper(Request.RequestContext);
string url = Request.Url.GetLeftPart(UriPartial.Authority)
+ urlHelper.Action("ViewReport",
new { userId = UserName, reportId = PI.ElementAt(i).TempUserID });
Or, if you prefer not to use the UrlHelper.Action, you do it like this:
string url = Request.Url.GetLeftPart(UriPartial.Authority) + "/ViewReport...";

Breeze is not working with some project settings

I have a problem using breeze on a project based on John Papa's HotTowel. I configured breeze like:
var mgr = new breeze.EntityManager('breeze/Breeze');
everything is ok but in the case I change the Project properties Start Action from Current Page to Specific Page: HotTowel/Index and breeze doesn't work properly.
I've checked the requests using firebug. It seems in this case application sends a GET request like this:
http://localhost:53180/HotTowel/Index/breeze/Breeze/Metadata
instead of
http://localhost:53180/breeze/Breeze/Metadata
I've also checked this part of breeze.js which is going to send get request.
The url parameter is set to breeze/Breeze/Metadata in both cases which seems correct.
ctor.prototype.fetchMetadata = function (metadataStore, dataService) {
var serviceName = dataService.serviceName;
var url = dataService.makeUrl("Metadata");
var deferred = Q.defer();
var that = this;
ajaxImpl.ajax({
url: url,
dataType: 'json',...
I've also tried ~/breeze/Breeze but it didn't work as remote service name.
As I'm new to web, probably it's not related to breeze.
The question is why the ajax call (or breeze) depends on how the project activates?
Add a / character to your configuration to execute the request relative to the base directory:
var mgr = new breeze.EntityManager('/breeze/Breeze');
The reason why this happens is because you specified a relative path for the EntityManager and if your url is localhost:53180/HotTowel/Index then the relative url for the EntityManager is localhost:53180/HotTowel/Index + /breeze/Breeze.
To correct the issue, change your EntityManager path to the following:
var mgr = new breeze.EntityManager('breeze/Breeze');

Resources