I don't want the extension of my HTML files to show up in the address bar like index.html, login.html. Instead, I want these files to be accessed with patterns like /HOMEPAGE /LOGIN
I don't hold these files under the resources/META-INF/resources directory because I also don't want these files to be accessed directly from the address bar by typing the file name.
I could not find a built-in solution in Quarkus to meet these needs. So I followed my own solution.
#GET
#Produces(MediaType.TEXT_HTML)
#Path("/LOGIN")
public String loginPage() throws IOException {
String fullPath = PATH + "login.html";
return Files.readString(Paths.get( fullPath ));
}
But I'm not sure if this is the right solution. Are there any best practices on Quarkus for the kind of needs I mentioned?
Using Quarkus Reactive Routes, you can create a route like:
#ApplicationScoped
public class StaticContentDeclarativeRoute {
#Route(path = "/homepage", methods = Route.HttpMethod.GET)
void indexContent(RoutingContext rc) {
StaticHandler.create(FileSystemAccess.RELATIVE, "content/index.html").handle(rc);
}
}
so that in this way at the URL /homepage you'll have the index.html page served.
Consider the path can also be absolute using FileSystemAccess.ROOT.
Related
How can I get #Url.Content() working in my _Layout.cshtml when RazorEngine is being used from ASP.NET Web API?
RazorEngine (v.3.7.2) only deals with the Razor syntax and not the additional helper methods like #Html or #Url. These can be added by extending the TemplateBase<> and setting it in the configuration.
There are code examples in some old issues: #26, #29; in an unreleased, incomplete piece of code in MvcTemplateBase.cs; and in the documentation for Extending the Template Syntax.
My problem is I'm using ASP.NET Web API (v.1) which won't have HttpContext.Current (nor should it). I want to provide a UrlHelper as I want to use its Content() method but it needs to be instantiated with the HttpRequestMessage which won't be available.
Perhaps there's no way to get #Url helper methods for my compiled layout. Perhaps I need some other way of getting the absolute path from the virtual path. It seems I'd still need some way of checking the Request though.
A way to get this working is to follow the direction set by Extending the Template Syntax and use VirtualPathUtility.ToAbsolute() in a helper method.
using System.Web;
using RazorEngine.Templating;
namespace MyNamespace.Web
{
public abstract class WebApiTemplateBase<T> : TemplateBase<T>
{
protected WebApiTemplateBase()
{
Url = new UrlHelper();
}
public UrlHelper Url;
}
public class UrlHelper
{
public string Content(string content)
{
return VirtualPathUtility.ToAbsolute(content);
}
}
}
Set up the TemplateService configuration with this extension of the TemplateBase<>.
var config =
new RazorEngine.Configuration.TemplateServiceConfiguration
{
TemplateManager = new TemplateManager(),
BaseTemplateType = typeof(WebApiTemplateBase<>)
};
I've used WebAPI for a while, and generally set it to use camel case json serialization, which is now rather common and well documented everywhere.
Recently however, working on a much larger project, I came across a more specific requirement: we need to use camel case json serialization, but because of backward compatibility issues with our client scripts, I only want it to happen for specific actions, to avoid breaking other parts of the (extremely large) website.
I figure one option is to have a custom content type, but that then requires client code to specify it.
Is there any other option?
Thanks!
Try this:
public class CamelCasingFilterAttribute : ActionFilterAttribute
{
private JsonMediaTypeFormatter _camelCasingFormatter = new JsonMediaTypeFormatter();
public CamelCasingFilterAttribute()
{
_camelCasingFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
}
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
ObjectContent content = actionExecutedContext.Response.Content as ObjectContent;
if (content != null)
{
if (content.Formatter is JsonMediaTypeFormatter)
{
actionExecutedContext.Response.Content = new ObjectContent(content.ObjectType, content.Value, _camelCasingFormatter);
}
}
}
}
Apply this [CamelCasingFilter] attribute to any action you want to camel-case. It will take any JSON response you were about to send back and convert it to use camel casing for the property names instead.
I have a requirement to render partial views using template files (.cshmtl) . The template file to be used for rendering will depend on a variety of parameters.
So the path may look like
~views/themes/student_themes/V1/Gen.cshtml or
~views/themes/student_themes/V2/Gen.cshtml or
~views/themes/teacher_themes/V1/Gen.cshtml or
~views/themes/student_themes/V2/Gen.cshtml or
Also V1 , V2 etc may go upto 20 Version directories
I have registered custom view path as
ViewEngines.Engines.Add(new TemplateViewEngine());
FreeSurvey.Web.Startup.DoStartup.Run();
}
}
class TemplateViewEngine : RazorViewEngine
{
private static string[] NewPartialViewFormats = new[] {
"~/Views/themes/theme_student/v2/{0}.cshtml" ,
"~/Views/themes/theme_student/v1/{0}.cshtml" ,
..
..
};
public TemplateViewEngine()
{
base.PartialViewLocationFormats = base.PartialViewLocationFormats.Union(NewPartialViewFormats).ToArray();
}
}
However since I have many such view paths it will become unwieldy. Is there a way to define
wild card path as "~/Views/themes/.*/.*/{0}.cshtml"
which is a better solution for me
I'm managing an MVC3 app where I need to support the ability of 3rd parties to create link to assets within my domain. Because some of the links are sliced and diced by mail merges and other text editing problems, URLs with typos have been introduced, e.g.:
/Content/ima!+ges/email/spacer.gif
or
/Content/image++s/email+/spacer.gif
I'd like to strip these extraneous characters by RegEx before attempting to serve them. I _think this is something a Route method could accomplish and I'd welcome a pointer or two to articles that demonstrate this approach.
ADDENDUM (cuz I need the formatting):
Implementing #Nathan's routing I'm unable to send the filename to the controller handler - it's always seeing a null value passed in. I've tried both 'filepath' and 'path' with the same 'null' result.
routes.MapRoute(
"MangledFilename",
"{*filepath}",
new { controller = "MangledFilename", action = "ServeFile" }
);
I think this is a matter of configuring wildcard handling on IISExpress and am looking for that solution separately. The more serious immediate problem is how your suggestion returns the HttpNotFound - i'm getting a hard IIS exception (execution halts with a YellowScreenDeath) instead of the silent 404 result.
public ActionResult ServeFile(string filePath)
{
if (filePath != null) // workaround the null
{
...
}
return HttpNotFound();
}
thx
I think something along this approach should work:
First add a route like this to the end of your route registering declarations:
routes.MapRoute(
"MangledFilename",
"{*filepath}",
new { controller = "MangledFilename", action = "ServeFile" });
If you haven't seen them before, a route parameter with an * after the opening { is a wildcard parameter, in this case it will match the entire path. You could also write it like content/{*filepath} if you wanted to restrict this behavior to your content directory.
And then a controller something like this should do the trick:
public class MangledFilenameController : Controller
{
public ActionResult ServeFile(string filePath)
{
filePath = CleanFilePath(filePath);
var absolutePath = Server.MapPath(filePath);
if (System.IO.File.Exists(absolutePath))
{
var extension = System.IO.Path.GetExtension(absolutePath);
var contentType = GetContentTypeForExtenion(extension);
return File(absolutePath, contentType);
}
return HttpNotFound();
}
private string CleanFilePath(string filepath)
{
//clean the path up
return filepath;
}
private string GetContentTypeForExtenion(string extension)
{
//you will want code here to map extensions to content types
return "image/gif";
}
}
In regards to mapping an extension to a MIME / content type for the GetContentTypeForExtension method, you could choose to hard code types you are expecting to serve, or use one of the solutions detailed in this post:
File extensions and MIME Types in .NET
EDIT:
After thinking about it, I realized there's another way you can handle the ServeFile action. Redirecting to the existing file could be simpler. I'm leaving the original method I wrote above and adding the alternative one here:
public ActionResult ServeFile(string filePath)
{
filePath = CleanFilePath(filePath);
var absolutePath = Server.MapPath(filePath);
if (System.IO.File.Exists(absolutePath))
{
return RedirectPermanent(filePath);
}
return HttpNotFound();
}
I believe #Nathan Anderson provided a good answer but it seems incomplete.
If you want to correct the typos and the types are as simple as those you mentioned then you can use Nathan code but before trying to find the file, you remove any plus or exclamation point characters in the path and you can do it like this:
String sourcestring = "source string to match with pattern";
String matchpattern = #"[+!]";
String replacementpattern = #"";
Console.WriteLine(Regex.Replace(sourcestring,matchpattern,replacementpattern));
Generated this code from the My Regex Tester tool.
This is the code you need. This code also removes any + character from the filename. If you don't want that behavior, you may select a substring without the filename and only replace + and ! characters before the filename.
I would like to break out my controllers and views into separate class libraries so they can be reused in multiple ASP.NET MVC 3 applications. The controllers part was not an issue when using a separate assembly, however getting the view engine to locate the view was.
I ended up using Compile your asp.net mvc Razor views into a seperate dll.
Is there an easier way that I missed?
I have modified the idea posted here, to work with MVC3. It was pretty fast and easy. The only minor drawback is that shared views need to be embedded resources, and therefore, compiled.
Put your shared views (.cshtml, .vbhtml files) into a library project. (I also have some shared controllers in this project.) If you want to use the _Layout.cshtml from your application, make sure you include a _ViewStart.cshtml, that points to it, in with your shared views.
In the library project, set all of your views' Build Action properties to Embedded Resource.
In the library project add the following code which will write the contents of your views to a tmp/Views directory.
.
public class EmbeddedResourceViewEngine : RazorViewEngine
{
public EmbeddedResourceViewEngine()
{
ViewLocationFormats = new[] {
"~/Views/{1}/{0}.aspx",
"~/Views/{1}/{0}.ascx",
"~/Views/Shared/{0}.aspx",
"~/Views/Shared/{0}.ascx",
"~/Views/{1}/{0}.cshtml",
"~/Views/{1}/{0}.vbhtml",
"~/Views/Shared/{0}.cshtml",
"~/Views/Shared/{0}.vbhtml",
"~/tmp/Views/{0}.cshtml",
"~/tmp/Views/{0}.vbhtml"
};
PartialViewLocationFormats = ViewLocationFormats;
DumpOutViews();
}
private static void DumpOutViews()
{
IEnumerable<string> resources = typeof(EmbeddedResourceViewEngine).Assembly.GetManifestResourceNames().Where(name => name.EndsWith(".cshtml"));
foreach (string res in resources) { DumpOutView(res); }
}
private static void DumpOutView(string res)
{
string rootPath = HttpContext.Current.Server.MapPath("~/tmp/Views/");
if (!Directory.Exists(rootPath))
{
Directory.CreateDirectory(rootPath);
}
Stream resStream = typeof(EmbeddedResourceViewEngine).Assembly.GetManifestResourceStream(res);
int lastSeparatorIdx = res.LastIndexOf('.');
string extension = res.Substring(lastSeparatorIdx + 1);
res = res.Substring(0, lastSeparatorIdx);
lastSeparatorIdx = res.LastIndexOf('.');
string fileName = res.Substring(lastSeparatorIdx + 1);
Util.SaveStreamToFile(rootPath + fileName + "." + extension, resStream);
}
}
I'm using Adrian's StreamToFile writer, found here.
In the Global.asax.cs of your application add:
.
public static void RegisterCustomViewEngines(ViewEngineCollection viewEngines)
{
//viewEngines.Clear(); //This seemed like a bad idea to me.
viewEngines.Add(new EmbeddedResourceViewEngine());
}
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
RegisterCustomViewEngines(ViewEngines.Engines);
}
Take a look at mvc contrib's portable areas:
http://www.lostechies.com/blogs/hex/archive/2009/11/01/asp-net-mvc-portable-areas-via-mvccontrib.aspx
They were made specifically for this purpose. If you go that road, it is less code you have to mantain ;-)
Just a few additions to Carson Herrick's excellent post...
You will need to resolve a few of the references (you will need to include System.Runtime.Remoting into your project).
Utils.SaveStreamToFile needs to be changed to ->
System.Runtime.Remoting.MetadataServices.MetaData.SaveStreamToFile(resStream, rootPath + fileName + "." + extension);
You may get the error - The view must derive from WebViewPage, or WebViewPage<TModel>. The answer is here: The view must derive from WebViewPage, or WebViewPage<TModel>
When you deploy the project, it is highly likely you will get an error when you load the project. You need to give the APP POOL you are using (full) rights to the folder.