I am replacing a Project built using ASP.NET WebForms and I need to replace the .ashx Generic Handlers - but I need to keep the page names so an app that has these URIs hardcoded does not require updating.
I know how to deal with the logic, that is not the problem. The problem is that these pages are referenced by an app that I do not want to update, so I need to be able to use URIs that point to pages ending in .ashx.
I have tried everything I can think of. I had hoped to just use the #page directive as shown below:
#page "/mygenerichandler.ashx"
Unfortunately, that does not work. If it did, I would be all set.
I have seen pages telling me to handle the .ashx as a sort of parameter:
#page "/mygenerichandler/{ashx}" (and variations of this, none work)
This does not work.
I have tried just naming the pages with the .ashx extension. This does not work.
I do not want to have to update the apps that have the URLs embedded in them, but it is looking more and more like that is my only option.
Is there any way to accept a page request in Blazor to a page that is named something like "mygenerichandler.ashx"?
I figured it out. I am using the Middleware Pattern, and it turns out that this will execute early in the pipeline and allow me to inspect the URL for the .ashx extension and then route accordingly. I should be able to return a response from this point - I still have to implement that code, but it is not directly germane to this question so I will not cover it here.
public class HandlerTrapper
{
private readonly RequestDelegate _next;
public string? AccountID { get; set; }
public HandlerTrapper(RequestDelegate next)
{
_next = next;
}
public Task Invoke(HttpContext httpContext) //, [FromQuery(Name = "AccountID")] string accountId
{
string? page = httpContext.Request.Path.Value?.Replace(#"/", "");
Console.WriteLine("Page Name is {0}, AccountID = {1}", page, AccountID);
if(page==null || !page.Contains(".ashx"))
return _next(httpContext);
AccountID = httpContext.Request.Query["AccountID"];
switch (page)
{
case "GetAmzRefreshToken":
break;
}
return _next(httpContext);
}
private
}
// Extension method used to add the middleware to the HTTP request pipeline.
public static class HandlerTrapperExtensions
{
public static IApplicationBuilder UseHandlerTrapper(this IApplicationBuilder builder)
{
return builder.UseMiddleware<HandlerTrapper>();
}
}
This is called as shown here in Program.cs:
app.UseHandlerTrapper();
I am pretty sure I can just return a Response from here and after implementing the code that does the work based on the incoming legacy page name, I should have a replacement for my .ashx Generic Handlers.
There is an even better solution which I implemented in my code. The WebApplication class has a UrlReWriter method that solves this problem quite elegantly when used in conjunction with the Controller Routing.
I added these lines to my Program.cs file - I placed them before the UseHttpRedirection and the UseRouting calls.:
RewriteOptions urlOptions = new RewriteOptions().AddRewrite(#"^(.*).ashx$", "api/$1", false);
urlOptions.AddRewrite(#"^(.*).inf$", "api/ComputerInfo", false);
app.UseRewriter(urlOptions);
That resolved the issue for both of the file type patterns I needed to handle, and I can add more if need be.
Related
I am looking for existing solutions to match dynamic parameters with HttpCore. What I have in mind is something similar to constraints in ruby on rails, or dynamic parameters with sails (see here for example).
My objective is to define a REST API where I could easily match requests like GET /objects/<object_id>.
To give a little bit of context, I have an application that creates an HttpServer using the following code
server = ServerBootstrap.bootstrap()
.setListenerPort(port)
.setServerInfo("MyAppServer/1.1")
.setSocketConfig(socketConfig)
.registerHandler("*", new HttpHandler(this))
.create();
And the HttpHandler class that matches the requested URI and dispatches it to the corresponding backend method:
public void handle(final HttpRequest request, final HttpResponse response, final HttpContext context) {
String method = request.getRequestLine().getMethod().toUpperCase(Locale.ROOT);
// Parameters are ignored for the example
String path = request.getRequestLine().getUri();
if(method.equals("POST") && path.equals("/object/add") {
if(request instanceof HttpEntityEnclosingRequest) {
addObject(((HttpEntityEnclosingRequest)request).getEntity())
}
[...]
For sure I can replace path.equals("/object/add") by something more sophisticated with RegEx to match these dynamic parameters, but before doing so I'd like to know if I am not reinventing the wheel, or if there is an existing lib/class I didn't see in the docs that could help me.
Using HttpCore is a requirement (it is already integrated in the application I am working on), I know some other libraries provide high-level routing mechanisms that support these dynamic parameters, but I can't really afford switching the entire server code to another library.
I am currently using httpcore 4.4.10, but I can upgrade to a newer version of this might help me.
At present HttpCore does not have a fully featured request routing layer. (The reasons for that are more political than technical).
Consider using a custom HttpRequestHandlerMapper to implement your application specific request routing logic.
final HttpServer server = ServerBootstrap.bootstrap()
.setListenerPort(port)
.setServerInfo("Test/1.1")
.setSocketConfig(socketConfig)
.setSslContext(sslContext)
.setHandlerMapper(new HttpRequestHandlerMapper() {
#Override
public HttpRequestHandler lookup(HttpRequest request) {
try {
URI uri = new URI(request.getRequestLine().getUri());
String path = uri.getPath();
// do request routing based on the request path
return new HttpFileHandler(docRoot);
} catch (URISyntaxException e) {
// Provide a more reasonable error handler here
return null;
}
}
})
.setExceptionLogger(new StdErrorExceptionLogger())
.create();
I was experimenting with Bundle and Minification in MVC4 and came across an interesting problem.
I am using Coffeescript and I would like a Render helper that works a bit like the #Scripts.Render() method.
For example, let's say I have this bundle config:
new ScriptBundle("~/bundle/appfiles").Include(
"~/Scripts/app/sample.js",
"~/Scripts/app/myApp.js");
In the cshtml, when I do #Scripts.Render() I get different results based on the debug setting in the web.config. If debug is true I get one script tag per file, otherwise I get a single script tag that returns the bundled and minified js. This is fine.
Let-s assume now that I want to do the same with my Coffeescripts. I create a bundle like this:
new Bundle("~/bundle/appfiles", new CoffeeBundler(), new JsMinify()).Include(
"~/Scripts/app/sample.coffee",
"~/Scripts/app/myApp.coffee");
The problem now is that if I use #Scripts.Render() I get, while in debug, one script per file but this is not transformed at all. The only use I could do is this:
<script type="text/javascript" src="#(BundleTable.Bundles.ResolveBundleUrl("~/bundle/appfiles"))"></script>
But this will, even in debug mode, bundle everything together and then minify, which of course is not what I want.
I have tried to create a Coffee.Render() helper similar to the Scripts one but it uses the AssetManager class which is internal to the System.Web.Optimization assembly.
I was wondering if you have an idea on how to do this in a clean way (i.e: using the available public classes, not copying and pasting the whole AssetManager code, not doing fancy Directory.EnumerateFiles when creating the bundle).
Thanks!
PS: I know that a quicker solution would be to use Mindscape Workbench and bundle the generated js files, I am looking for something that uses what the framework has, maybe also avoiding to have to tell the team to install a tool that people may not like...
In the end I went for a HtmlHelper solution for this. Still in early stage but working as I would like. It is detailed in a blog post for the time being.
Here is the full Helper code in case the blog goes lost...
public static class HtmlHelperExtensions
{
public static MvcHtmlString RenderCoffeeBundle(this HtmlHelper htmlHelper, string virtualPath)
{
if (String.IsNullOrEmpty(virtualPath))
throw new ArgumentException("virtualPath must be defined", "virtualPath");
var list = GetPathsList(virtualPath);
//TODO: Nice and cleaner EliminateDuplicatesAndResolveUrls(list);
var stringBuilder = new StringBuilder();
foreach (string path in list)
{
stringBuilder.Append(RenderScriptTag(path));
stringBuilder.Append(Environment.NewLine);
}
return MvcHtmlString.Create(stringBuilder.ToString());
}
private static IEnumerable<string> GetPathsList(string virtualPath)
{
var list = new List<string>();
if (BundleResolver.Current.IsBundleVirtualPath(virtualPath))
{
if (!BundleTable.EnableOptimizations)
{
foreach (var path in BundleResolver.Current.GetBundleContents(virtualPath))
{
var bundlePath = "~/autoBundle" + ResolveVirtualPath(path.Replace("coffee", "js"));
BundleTable.Bundles.Add(new Bundle(bundlePath, new CoffeeBundler()).Include(path));
// TODO: Get the actual CustomTransform used in the Bundle
// rather than forcing "new CoffeeBundler()" like here
list.Add(bundlePath);
}
}
else
list.Add(BundleResolver.Current.GetBundleUrl(virtualPath));
}
else
list.Add(virtualPath);
return list.Select(ResolveVirtualPath).ToList();
}
private static string RenderScriptTag(string path)
{
return "<script src=\"" + HttpUtility.UrlPathEncode(path) + "\"></script>";
}
private static string ResolveVirtualPath(string virtualPath)
{
return VirtualPathUtility.ToAbsolute(virtualPath);;
}
}
I'm sorry I'm not addressing your exact question, but I do want to speak to your PS at the end of the post.
At this time, I don't really think we have a "no tools" story, but I do agree with the sentiment of "using what the framework has".
To that end, I would strongly recommend using TypeScript. You don't have to learn a new language (like you do with CoffeeScript) and yet it gives you a strongly-typed version of JavaScript that you can use a lot more like c# (with type validation etc.).
It will take you 20 mins to go through some of the tutorials:
http://www.typescriptlang.org/Playground/
Or, better yet, have a look at the BUILD session from the fall:
http://channel9.msdn.com/Events/Build/2012/3-012
Btw...if this isn't a direction you are wanting to go, no worries...I just find a lot of devs don't even know about TypeScript yet as an option.
Hope this helps in your quest to simplify things for your team.
Cheers.
When you call RazorEngine.Razor.Compile(), where is the compiled template stored?
Is it available after the programs been restarted? If there is a memory shortage, will it be dumped?
I am using RazorEngine in an ASP.NET (MVC) project. Will the precompiled templates be available after the application restarts?
Would it make more sense for me to store them in the HttpContext.Cache?
If I did, then would it make more sense to use a different function (other than Compile) that bypasses the internal cache? Is there a way to execute an ITemplate and just pass it a model?
Does RazorEngine.Razor.Parse() do any caching? Or is the template recompiled each time?
Currently, after the RazorEngine compiles the templates, they are loaded into memory. These assemblies persist in memory only and do not continue beyond the lifetime of the application.
I am considering adding in support for compiling these assemblies to files, but that'll be a future version.
If you call Razor.Parse and pass in a name for the template, it will attempt to
Check the cache of in-memory assemblies for an assembly with the same name.
Invalid the cache of the content of the template has changed.
Cache the newly compiled template.
I've got this to work with RazorEngine 3.4.1.0, installed late Jan 2014.
The key is to call the expensive Razor.Compile(content, name) to put the template into cache, then call the cheap Razor.Run(name, model) to execute the template.
Remember that reading template content might be expensive -- say, involving a read from disk -- so my solution only gets template content once. This might be too much caching for you, so careful!
Here's the RenderPartial method I use inside a custom TemplateBase<T> subclass. It runs very quickly for multiple calls to the same template.
public abstract class SqlTemplate<T>: TemplateBase<T>
{
public string RenderPartial(string templateName, object model = null)
{
// loading a template might be expensive, so be careful to cache content
if (Razor.Resolve(templateName) == null)
{
// we've never seen this template before, so compile it and stick it in cache.
var templateContent = GetTemplateContent(templateName);
Razor.Compile(templateContent, templateName);
}
// by now, we know we've got a the template cached and ready to run; this is fast
var renderedContent = Razor.Run(templateName, model);
return renderedContent;
}
private string GetTemplateContent(string templateName)
{
... your implementation here
}
}
You also need to tell Razor to use this base class (SqlTempalte<T>) which you can do like this, by calling RazorEngineConfigurator.Configure();
public static class RazorEngineConfigurator
{
private static bool configured = false;
public static void Configure()
{
if (configured)
{
return;
}
var templateConfig = new TemplateServiceConfiguration
{
BaseTemplateType = typeof(SqlTemplate<>),
EncodedStringFactory = new RazorEngine.Text.RawStringFactory()
};
RazorEngine.Razor.SetTemplateService(new TemplateService(templateConfig));
configured = true;
}
}
Couldn't have done it without this SO answer -- why not give that one an up-vote, too? :)
Edit - If you need to perform caching in a more granular way, you'll need to use a different approach using RazorEngineTemplateService and ITemplateResolver.
Here's a piece of starter code;
public static RazorEngineTemplateService CreateService(ITemplateResolver resolver, ICollection<string> namespaces)
{
Check.IsNotNull(resolver, "resolver");
var config = new TemplateServiceConfiguration();
config.BaseTemplateType = typeof(PlainTextTemplate<>);
config.EncodedStringFactory = new RazorEngine.Text.RawStringFactory();
config.Resolver = resolver;
config.Namespaces = new HashSet<string>(namespaces);
var service = new RazorEngineTemplateService(config);
return service;
}
ITemplateResolver turns template names into template contents, so you can implement, eg, a CachedFileTemplateResolver which loads cached content from disk.
I am writing a web application using Spring MVC. I am using annotations for the controllers, etc. Everything is working fine, except when it comes to actual links in the application (form actions, <a> tags, etc.) Current, I have this (obviously abbreviated):
//In the controller
#RequestMapping(value="/admin/listPeople", method=RequestMethod.GET)
//In the JSP
Go to People List
When I directly enter the URL like "http://localhost:8080/MyApp/admin/listPeople", the page loads correctly. However, the link above does not work. It looses the application name "MyApp".
Does anyone know if there is a way to configure Spring to throw on the application name on there?
Let me know if you need to see any of my Spring configuration. I am using the standard dispatcher servlet with a view resolver, etc.
You need to prepend context path to your links.
// somewhere on the top of your JSP
<c:set var="contextPath" value="${pageContext.request.contextPath}"/>
...
Go to People List
The c:url tag will append the context path to your URL. For example:
<c:url value="/admin/listPeople"/>
Alternately, I prefer to use relative URLs as much as possible in my Spring MVC apps as well. So if the page is at /MyApp/index, the link <a href="admin/listPeople"> will take me to the listPeople page.
This also works if you are deeper in the URL hierarchy. You can use the .. to traverse back up a level. So on the page at/MyApp/admin/people/aPerson, using <a href="../listPeople"> will like back to the list page
I prefer to use BASE tag:
<base href="${pageContext.request.scheme}://${pageContext.request.serverName}:${pageContext.request.serverPort}${pageContext.request.contextPath}/" />
Then, all your links can be like:
Go to People List
As i have just been trying to find the answer to this question and this is the first google result.
This can be done now using the MvcUriComponentsBuilder
This is part of the 4.0 version of Spring MVC
http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/servlet/mvc/method/annotation/MvcUriComponentsBuilder.html
The method needed is fromMappingName
From the documentation :
Create a URL from the name of a Spring MVC controller method's request mapping.
The configured HandlerMethodMappingNamingStrategy determines the names of controller method request mappings at startup. By default all mappings are assigned a name based on the capital letters of the class name, followed by "#" as separator, and then the method name. For example "PC#getPerson" for a class named PersonController with method getPerson. In case the naming convention does not produce unique results, an explicit name may be assigned through the name attribute of the #RequestMapping annotation.
This is aimed primarily for use in view rendering technologies and EL expressions. The Spring URL tag library registers this method as a function called "mvcUrl".
For example, given this controller:
#RequestMapping("/people")
class PersonController {
#RequestMapping("/{id}")
public HttpEntity getPerson(#PathVariable String id) { ... }
}
A JSP can prepare a URL to the controller method as follows:
<%# taglib uri="http://www.springframework.org/tags" prefix="s" %>
Get Person
I usually configure tomcat to use context root of "/" or deploy the war as ROOT.war. Either way the war name does not become part of the URL.
You could use a servletRelativeAction. I'm not sure what versions this is available in (I'm using 4.0.x currently) and I haven't seen much documentation on this, but if you look at the code backing the spring form you can probably guess. Just make sure the path you pass it starts with a "/".
Example:
<form:form class="form-horizontal" name="form" servletRelativeAction="/j_spring_security_check" method="POST">
See org.springframework.web.servlet.tags.form.FormTag:
protected String resolveAction() throws JspException {
String action = getAction();
String servletRelativeAction = getServletRelativeAction();
if (StringUtils.hasText(action)) {
action = getDisplayString(evaluate(ACTION_ATTRIBUTE, action));
return processAction(action);
}
else if (StringUtils.hasText(servletRelativeAction)) {
String pathToServlet = getRequestContext().getPathToServlet();
if (servletRelativeAction.startsWith("/") && !servletRelativeAction.startsWith(getRequestContext().getContextPath())) {
servletRelativeAction = pathToServlet + servletRelativeAction;
}
servletRelativeAction = getDisplayString(evaluate(ACTION_ATTRIBUTE, servletRelativeAction));
return processAction(servletRelativeAction);
}
else {
String requestUri = getRequestContext().getRequestUri();
ServletResponse response = this.pageContext.getResponse();
if (response instanceof HttpServletResponse) {
requestUri = ((HttpServletResponse) response).encodeURL(requestUri);
String queryString = getRequestContext().getQueryString();
if (StringUtils.hasText(queryString)) {
requestUri += "?" + HtmlUtils.htmlEscape(queryString);
}
}
if (StringUtils.hasText(requestUri)) {
return processAction(requestUri);
}
else {
throw new IllegalArgumentException("Attribute 'action' is required. " +
"Attempted to resolve against current request URI but request URI was null.");
}
}
}
Since it's been some years I thought I'd chip in for others looking for this. If you are using annotations and have a controller action like this for instance:
#RequestMapping("/new") //<--- relative url
public ModelAndView newConsultant() {
ModelAndView mv = new ModelAndView("new_consultant");
try {
List<Consultant> list = ConsultantDAO.getConsultants();
mv.addObject("consultants", list);
} catch (Exception e) {
e.printStackTrace();
}
return mv;
}
in your .jsp (view) you add this directive
<%#taglib uri="http://www.springframework.org/tags" prefix="spring"%>
and simply use
<spring:url value="/new" var="url" htmlEscape="true"/>
New consultant
where
value's value should match #RequestMapping's argument in the controller action and
var's value is the name of the variable you use for href
HIH
A database application that I'm currently working on, stores all sorts of settings in the database. Most of those settings are there to customize certain business rules, but there's also some other stuff in there.
The app contains objects that specifically do a certain task, e.g., a certain complicated calculation. Those non-UI objects are unit-tested, but also need access to lots of those global settings. The way we've implemented this right now, is by giving the objects properties that are filled by the Application Controller at runtime. When testing, we create the objects in the test and fill in values for testing (not from the database).
This works better, in any case much better than having all those objects need some global Settings object --- that of course effectively makes unit testing impossible :) Disadvantage can be that you sometimes need to set a dozen of properties, or that you need to let those properties 'percolate' into sub-objects.
So the general question is: how do you provide access to global application settings in your projects, without the need for global variables, while still being able to unit test your code? This must be a problem that's been solved 100's of times...
(Note: I'm not too much of an experienced programmer, as you'll have noticed; but I love to learn! And of course, I've already done research into this topic, but I'm really looking for some first-hand experiences)
You could use Martin Fowlers ServiceLocator pattern. In php it could look like this:
class ServiceLocator {
private static $soleInstance;
private $globalSettings;
public static function load($locator) {
self::$soleInstance = $locator;
}
public static function globalSettings() {
if (!isset(self::$soleInstance->globalSettings)) {
self::$soleInstance->setGlobalSettings(new GlobalSettings());
}
return self::$soleInstance->globalSettings;
}
}
Your production code then initializes the service locator like this:
ServiceLocator::load(new ServiceLocator());
In your test-code, you insert your mock-settings like this:
ServiceLocator s = new ServiceLocator();
s->setGlobalSettings(new MockGlobalSettings());
ServiceLocator::load(s);
It's a repository for singletons that can be exchanged for testing purposes.
I like to model my configuration access off of the Service Locator pattern. This gives me a single point to get any configuration value that I need and by putting it outside the application in a separate library, it allows reuse and testability. Here is some sample code, I am not sure what language you are using, but I wrote it in C#.
First I create a generic class that will models my ConfigurationItem.
public class ConfigurationItem<T>
{
private T item;
public ConfigurationItem(T item)
{
this.item = item;
}
public T GetValue()
{
return item;
}
}
Then I create a class that exposes public static readonly variables for the configuration item. Here I am just reading the ConnectionStringSettings from a config file, which is just xml. Of course for more items, you can read the values from any source.
public class ConfigurationItems
{
public static ConfigurationItem<ConnectionStringSettings> ConnectionSettings = new ConfigurationItem<ConnectionStringSettings>(RetrieveConnectionString());
private static ConnectionStringSettings RetrieveConnectionString()
{
// In .Net, we store our connection string in the application/web config file.
// We can access those values through the ConfigurationManager class.
return ConfigurationManager.ConnectionStrings[ConfigurationManager.AppSettings["ConnectionKey"]];
}
}
Then when I need a ConfigurationItem for use, I call it like this:
ConfigurationItems.ConnectionSettings.GetValue();
And it will return me a type safe value, which I can then cache or do whatever I want with.
Here's a sample test:
[TestFixture]
public class ConfigurationItemsTest
{
[Test]
public void ShouldBeAbleToAccessConnectionStringSettings()
{
ConnectionStringSettings item = ConfigurationItems.ConnectionSettings.GetValue();
Assert.IsNotNull(item);
}
}
Hope this helps.
Usually this is handled by an ini file or XML configuration file. Then you just have a class that reads the setting when neeed.
.NET has this built in with the ConfigurationManager classes, but it's quite easy to implement, just read text files, or load XML into DOM or parse them by hand in code.
Having config files in the database is ok, but it does tie you to the database, and creates an extra dependancy for your app that ini/xml files solve.
I did this:
public class MySettings
{
public static double Setting1
{ get { return SettingsCache.Instance.GetDouble("Setting1"); } }
public static string Setting2
{ get { return SettingsCache.Instance.GetString("Setting2"); } }
}
I put this in a separate infrastructure module to remove any issues with circular dependencies.
Doing this I am not tied to any specific configuration method, and have no strings running havoc in my applications code.