Intercepting requests and providing resources to Xamarin.Forms.WebView - c#

I want to show some XHTML documents that reference some resources (style sheets, scripts, images, etc). These resources are local, but they do not exist on the file system - instead, they are generated by my application.
Using Android.Webkit.WebView and Android.Webkit.WebViewClient, I can intercept requests and provide these resources flawlessly, using something like this:
internal class MyWebViewClient : WebViewClient
{
public override WebResourceResponse ShouldInterceptRequest (WebView view, string url)
{
/* logic to create a resource stream for the requested url */
return new WebResourceResponse (mimeType, encoding, generatedStream);
}
}
Can I achieve something similar using Xamarin.Forms.WebView and its related classes? If so, how? I haven't noticed in the API documentation any methods that look like they provide equivalent behavior.

The Xamarin.Forms WebView control is very basic at present. The class members show that you wouldn't be able achieve what you are wanting to do.
You can load a HTML resource etc here that is quite useful in determining how to reference local files, if you do decide and go down that route.
Do note, however, that in Xamarin.Forms v1.2.2.6243 on Android the Source property is incorrectly set for URLs. For instance, if you navigate to www.yahoo.com and do a few clicks on that site, you will see some query string parameters etc. However, on Android this always comes back as Source property being www.yahoo.com. Xamarin have created a temporary fix for this, however you have to include and implement your own custom renderer at present to overcome this.

Related

Server side custom control rendering in ASP.NET Core 1.0

Anyone know good behavior for creating server side logic for render custrom control in ASP vNext? I read about tag helpers but i don't know that is the best solution for me. The expected end solution should look similar to:
public class CustomControl : Control //here base class with context etc
{
public override void Render()
{
using (var control = _context.Div())
{
input.AddAttribute(HtmlTextWriterAttribute.Content, "Div");
}
}
}
I'm looking for good documentation that help me implement base Control class.
Server side custom controls were a solution to a bad ASP.NET design.
vNEXT is design to not have these same types of problems, and while you could try to reimplement the same bad design issues, you should instead look at using direct HTML rendering and / or JSON, and then let the browser handle the complications with something like HandlebarsJS
also by offloading most of the work to the browser your server will be able to handle a far higher user load.

Set xmlrpc.net service url at runtime

I like to interact with some of my wordpress blogs through xmlrpc interface. During my research I found xml-rpc.net-Library (www.xml-rpc.net) which works really fine except for one thing.
I build my xmlrpc.net instance like this:
[XmlRpcUrlAttribute("http://my-example-blog.com/xmlrpc.php")]
public class WP : XmlRpcClientProtocol
{
public WP()
{
}
...
}
But I want to set the xmlrpc-Url dynamically during runtime. So I like to add more blogs during the UI at runtime and don't want to implement each blog "hard-coded".
Does anybody had a same problem and can help me? Is there another possibility within xmlrpc.net-library or do you know another good xmlrpc library?
Greets,
Raffi
You can specify the URL at runtime:
proxy.Url = "http://my-example-blog.com/xmlrpc.php";

Custom ASP.NET callback-based routing; dynamic ASPX page instantiation and rendering

I'm working on a small school project, an ASP.NET C# website; we're working with a Web Application, using a Global.asax file to centralize request logic.
Anyway, my colleague and I are responsible for the coding in our group, and we both come as reasonably experienced PHP developers. We both rather enjoy working with the architectural style used by the PHP framework Laravel, using routes (callbacks associated with) as the "controllers", and (despite it being a square peg, round hole issue) are trying to replicate that functionality for this project.
This is no easy task; I've implemented the IRouteHandler interface as a CallbackRouteHandler in an attempt to start replicating this functionality:
public class CallbackRouteHandler : IRouteHandler
{
public Func<RequestContext, IHttpHandler> Callback { get; protected set; }
public CallbackRouteHandler(Func<RequestContext, IHttpHandler> callback)
{
this.Callback = callback;
}
public IHttpHandler GetHttpHandler(RequestContext requestContext)
{
return this.Callback(requestContext);
}
}
Unfortunately this is about as far as I've gotten. I'm reading through the ASP.NET Page Life Cycle Overview, attempting to understand better the entire process.
What we're stuck on is programmatically loading ASPX files (rather, instantiating as Page objects) in the scope of a given route callback. We were hoping there would be a reasonably easy way to accomplish, within the scope of the callback, something like:
// instantiate the target ASPX page object
OurSite.SomeNamespace.SomePage page = new OurSite.SomeNamespace.SomePage();
// manipulate the page object, setting public properties, etc.
page.SomeControl.Text = "Foobar!";
// eventually "render" the file to somehow; at this point, the
// page and it's associated code-behind events take control
page.Render();
I'm having trouble understanding both: 1) How to do this? 2) When (relative to the aforementioned page life-cycle) to do this.
How (if at all) can one accomplish this sort of functionality? I'm seeing that this process, hidden away by ASP.NET, is seemingly very complicated, but surely others have tread down this path before.
I went with MVC for this project, however I've since had the opportunity to dissect the ASP.NET request pipeline a bit, and have implemented custom routing solutions as warranted.

How can I get the URL of the current page from within a C# App_Code class?

I have a logging class that, well, logs things. I would like to add the ability to automatically have the current page be logged with the messages.
Is there a way to get the information I'm looking for?
Thanks,
From your class you can use the HttpContext.Current property (in System.Web.dll). From there, you can create a chain of properties:
Request
Url and RawUrl
The underlying object is a Page object, so if you cast it to that, then use any object you would normally use from within a Page object, such as the Request property.
It's brittle and hard to test but you can use System.Web.HttpContext.Current which will give you a Request property which in turn has the RawUrl property.
public static class MyClass
{
public static string GetURL()
{
HttpRequest request = HttpContext.Current.Request;
string url = request.Url.ToString();
return url;
}
}
I tried to break it down a little :)
In the past I've also rolled my own logging classes and used Console.Writeln() but really there are a number of good logging options that already exist so why go there? I use NLog pretty much everywhere; it is extremely flexible with various log output destinations including console and file, lots of log format options, and is trivial to set up with versions targeting the various .net frameworks including compact. Running the installer will add NLog config file options to the Visual Studio Add New Item dialog. Using in your code is simple:
// declare in your class
private static Logger logger = LogManager.GetCurrentClassLogger();
...
// use in your code
logger.Debug(() => string.Format("Url: {0}", HttpContext.Current.Request.Url));

CDN for Images in ASP.NET

I am in the process of moving all of the images in my web application over to a CDN but I want to easily be able to switch the CDN on or off without having to hard code the path to the images.
My first thought was to add an HttpHandler for image extensions that depending whether a variable in the web.config (something like ) will serve the image from the server or from the CDN. But after giving this a little though I think I've essentially ruled this out as it will cause ASP.NET to handle the request for every single image, thus adding overhead, and it might actually completely mitigate the benefits of using a CDN.
An alternative approach is, since all of my pages inherit from a base page class, I could create a function in the base class that determines what path to serve the files from based off the web.config variable. I would then do something like this in the markup:
<img src='<%= GetImagePath()/image.png' />
I think this is probably what I'll have to end up doing, but it seems a little clunky to me. I also envision problems with the old .NET error of not being able to modify the control collection because of the "<%=" though the "<%#" solution will probably work.
Any thoughts or ideas on how to implement this?
You've dismissed writing an HttpHandler based on an assumption of pre-optimization. I would revisit this and definitely write a simple HttpHandler and test it out. You might find that your Page method solution might even be slower, especially if you get the ASP preprocessor involved.
HttpHandlers are pretty close to the metal - it's a miniscule amount of overhead for IIS to hand the request to ASP.Net. It would be a more elegant solution than what you're proposing, and probably more scalable and I'm willing to bet - faster.
Have you considered a slightly simpler approach?
If your pages all inherit from a base class, you could expose a property on that which contains the prepend URL to your CDN (or, to your local server if you want to switch the CDN off). It is then a trivial matter of storing the prepend URL in the web.config:
public string PrependURLPath() {
get { return ConfigurationManager.AppSettings["ImagePrependURL"].ToString(); }
}
In your <appSettings/> element, you can simply choose what the prepend URL would be, eg:
http://my.cdn.com/user/
or:
http://my.own.server.com/images/
Pretty simple!
You would then be able to code your image refernces as per your example, but calling your base page property to expose the desired path:
<img src='<%= this.BasePage.PrependURLPath() + [YourImagePath.png] %>'/>
I agree that setting the image source through the inline call is messy, but you could probably do as someone else has suggested and then iterate through the image controls on your page, changing the prepend URL as you go.
Even if your pages currently only inherit from System.Web.UI.Page, it's a simple matter to create your own base class which inherits System.Web.Page, then do a find/replace in your solution on all remaining pages.
Hope this helps.
weighing in pretty late here, but i've been looking for a similar solution myself. searched google to sanity check what i had done. didn't consider the HttpHandler approach, what i did was simply extend the ASP.net Image control:
public class Img : Image
{
public Img()
{
RelativePath = false;
}
public bool RelativePath { get; set; }
public override string ImageUrl
{
get
{
if (RelativePath)
return base.ImageUrl;
return "http://some.configurable-value.com" + base.ImageUrl;
}
set { base.ImageUrl = value; }
}
}
it's rough and ready, but it works :) obviously it should rely on some configurable value rather than a string literal, but that's not a big change
If you display your images using tags you could create a control adapter, these allow you to alter the way .net controls render or universally alter them something like this should do the trick:
using System.Web.UI.WebControls.Adapters;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace ExampleCode
{
public class ImageAdapter : WebControlAdapter
{
private bool UseCdn
{
get { return true; } // Get value from config or anywhere else
}
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
Image image = (Image)Control;
if (UseCdn)
{
// If using relative urls for images may need to handle ~
image.ImageUrl = String.Format("{0}/{1}", "CDN URL", image.ImageUrl);
}
}
}
}
Then add a browser file to the App_Browsers folder in your web project like below:
<browsers>
<browser refID="Default">
<controlAdapters>
<adapter
controlType="System.Web.UI.WebControls.Image"
adapterType="ExampleCode.ImageAdapter"
/>
</controlAdapters>
</browser>
</browsers>
you could loop all controls and change the images url in the prerender event on your base class...
The good thing about the HTTP Handler approach is that it's quite re-usable and configurable: you can identify img paths to handle based on location - assuming the structure they're in helps this.
The possible drawback is that image file extensions (.jpg, .png, etc) aren't automatically passed on to the asp.net pipe-line; you can easily config IIS to do so - but you need to have a certain level of contriol over IIS - so it might not be an option if you're on a shared hosting environment.
I will go for #Rhys approach for image control.
Most of the time, I try to use background image css than using image control.
After that I upload both css and images together to the cloud and working fine for relative path.
Doesn't look like there has been an accepted answer yet so here is my suggestion. I had similar problems dealing with modifying URL's transparently (to a different end, but I thought about using it for CDN support as well).
This is an old filter / module but it worked well for my needs with a little tuning: http://www.paraesthesia.com/archive/2007/12/14/urlabsolutifiermodule---convert-urls-in-asp.net-output-to-absolute.aspx
What you can do is make a response filter and hook it with an httpmodule (as this absolutifier does). If you use this module + response filter you could probably achieve what you need by modifying the source for it to replace the hostname / prefix all urls to use the CDN.
I had to solve your problem and another one, that is I do not want to take resources from the CDN during development but only when the website is deployed on the production server.
To solve this I developed an ExpressionBuilder that prepends the CDN URL only in production.
<asp:Image ImageUrl="<%$ CdnUrl:/images/myimage.png %>" runat="server" />
In previous code the CDN URL will be prepended only in production.
namespace IdeaR.Web.Compilation
{
[ExpressionPrefix("CdnUrl")]
public class CdnUrlExpressionBuilder : ExpressionBuilder
{
public static object GetCdnUrl(string expression, Type target, string entry)
{
var retvalue = expression;
var productionUri = new Uri("http://www.myproductionurl.com",
UriKind.Absolute);
var currentUri = HttpContext.Current.Request.Url;
var cdnUrl = "http://cdn.mycdn.com";
// If this is a production website URL
if (currentUri.Scheme == productionUri.Scheme &&
currentUri.Host == productionUri.Host)
retvalue = cdnUrl + expression;
return retvalue;
}
public override CodeExpression GetCodeExpression(BoundPropertyEntry entry,
object parsedData, ExpressionBuilderContext context)
{
var componentType = entry.DeclaringType;
var expressionArray = new CodeExpression[3]
{
new CodePrimitiveExpression(entry.Expression.Trim()),
new CodeTypeOfExpression(componentType),
new CodePrimitiveExpression(entry.Name)
};
var descriptor = TypeDescriptor.GetProperties(componentType)
[entry.PropertyInfo.Name];
return new CodeCastExpression(descriptor.PropertyType,
new CodeMethodInvokeExpression(
new CodeTypeReferenceExpression(GetType()),
"GetCdnUrl", expressionArray));
}
}
}
For more information I wrote an article on this
How to use a CDN in production but not during development

Categories