Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Css File #33

Open
attiqe opened this issue Dec 15, 2018 · 4 comments
Open

Add Css File #33

attiqe opened this issue Dec 15, 2018 · 4 comments

Comments

@attiqe
Copy link

attiqe commented Dec 15, 2018

Hi,

Is it possible to add CSS file? I tried to add the CSS file with @Url.Content but it gives the following error:

Failed to render Layout Page: Line: 43, Column: 81, Error: The name 'ResolveUrl' does not exist in the current context

<link rel="stylesheet" href="@Url.Content("~/Content/EmailTemplate.css")" type="text/css" />

Thanks,
Attiqe

@RickStrahl
Copy link
Owner

RickStrahl commented Dec 27, 2018

There is no URL object in this implementation because it doesn't make sense to resolve external assets that way - there is no Web site so there's no base folder that you can point to.

You only have a folder and the folder has no bearing on where the output is actually rendered from because this engine doesn't actually run a site, it only produces the HTML that you then have to decide how to display (either locally from disk, or from your own Web site etc.)

I suppose we could replace the output with a hard file link:

<link href="file:///c:\myapp\renderedoutput\Content\EmailTemplate.css" type="text/css" />

But I'm not sure if that's the right way to go.

In short there's no clear way to express what ~ means in this context. It works for internal (Razor) constructs like RenderPartial() etc. because the engine actually loads those and can resolve the file names, but assets as above are not loaded by the engine but by the browser.

Your best bet is to use relative paths - relative to the where the rendered HTML will end up (most likely in the root of the template folder).

@RickStrahl
Copy link
Owner

Ok so I gave this some more thought and played around with this a little more. I suppose here's what could be done:

It's possible to resolve ~ relative to the current page. So for example you could have:

<link rel="stylesheet" href="~/Content/EmailTemplate.css" type="text/css" />

and if you are in a template that is /subfolder/mypage/test.cshtml you would end up with:

<link rel="stylesheet" href="../Content/EmailTemplate.css" type="text/css" />

But even so I think this is not what you'd want unless you are running a Web site and literally translating URLs just like MVC does in which case you shouldn't be using this library most likely but just use MVC.

Most rendering scenarios will capture the HTML and then use some other mechanism to render that HTML - a browser opened on disk (to preview) most likely or passed back to some other application that then decides to render. For all those scenarios these site relative links simply don't make sense because there's no site there to serve those relative images from.

@RickStrahl
Copy link
Owner

RickStrahl commented Dec 27, 2018

I've added the following code - be interested in comments:

/// <summary>
/// Resolves a ~ Url by removing ~ and using `/`
/// path.
///
/// This is not recommended for direct linked files in
/// HTML (scripts, images, css etc.) as these links may
/// not work properly.
/// </summary>
/// <param name="url"></param>
/// <returns></returns>
public virtual string ResolveUrl(string url)
{
   if(string.IsNullOrEmpty(url))
        return url;

    if (url.StartsWith("~"))
    {
        // only makes sense for folder based containers
        var host = this.HostContainer as RazorFolderHostContainer;
        if (host != null)
        {
            // create a full path for the URL, then create a relative URL to the current template
            url = url.Replace("~/", "").Replace("~", "");
            var fullPath = Path.Combine(host.TemplatePath, url);
            fullPath = GetRelativePath(fullPath, Path.GetDirectoryName(Request.TemplatePath));
            if (fullPath.Contains(":\\"))
                fullPath = "file:///" + fullPath;
            else
                fullPath = fullPath.Replace("\\", "/");

            return fullPath;
        }
    }

    return url;
}


/// <summary>
/// Returns a relative path string from a full path based on a base path
/// provided.
/// </summary>
/// <param name="fullPath">The path to convert. Can be either a file or a directory</param>
/// <param name="basePath">The base path on which relative processing is based. Should be a directory.</param>
/// <returns>
/// String of the relative path.
/// 
/// Examples of returned values:
///  test.txt, ..\test.txt, ..\..\..\test.txt, ., .., subdir\test.txt
/// </returns>
public static string GetRelativePath(string fullPath, string basePath)
{
    // ForceBasePath to a path
    if (!basePath.EndsWith(value: "\\"))
        basePath += "\\";

#pragma warning disable CS0618
    Uri baseUri = new Uri(uriString: basePath, dontEscape: true);
    Uri fullUri = new Uri(uriString: fullPath, dontEscape: true);
#pragma warning restore CS0618

    Uri relativeUri = baseUri.MakeRelativeUri(uri: fullUri);

    // Uri's use forward slashes so convert back to backward slahes
    return relativeUri.ToString().Replace(oldValue: "/", newValue: "\\");
}

It's in there now so at least direct references to ~ paths are not breaking any longer. No URL object though to make it clear that URL adjustments don't make sense in this scenario.

@attiqe
Copy link
Author

attiqe commented Feb 24, 2019

@RickStrahl sorry I just looked at the comments and I will try them and get back to you as soon as possible.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants