Rendering view from non-file source in Nancy - nancy

I have a fairly typical Nancy configuration, with views being served from locations on the file system.
Under a specific route I wish to serve views which are not stored on the file system, but will be provided in Markdown format from an external service.
I initially approached the idea by considering creating a custom concrete class for IViewLocationProvider which would deal with locating the views from the external service. By my understanding of Nancy (and I could be wrong here), you can only have one IViewLocationProvider, so adding this custom class would mean that I could not get the rest of the pages (for all my other routes) from the file system.
My approach is now to manually call the Nancy.ViewEngines.Markdown.Render method, passing it my Markdown (encapsulated in a Func<TextReader>) and a fake ViewLocationResult. As so:
public class MyModule
{
public MyModule(ExternalServiceAdapter externalService, MarkDownViewEngine viewEngine, IRenderContext renderContext) : base("/MyPath")
{
Get["/{Name}/{Version}/View"] = parameters => SpecialView(viewEngine, renderContext, externalService, (string)parameters.Name, (string)parameters.Version);
}
protected static Response SpecialView(MarkDownViewEngine viewEngine, IRenderContext renderContext, ExternalServiceAdapter externalService, string name, string version)
{
var contents = externalService.GetData(name, version);
var location = new ViewLocationResult(string.Empty, string.Empty, "md", contents);
return viewEngine.RenderView(location, null, renderContext); //FIXME fails when performing Master page substitution in Super Simple View Engine
}
}
Unfortunately the Markdown includes an SSVE #Master['master'] tag which causes the above to fall down at the indicated line with a null reference exception deep within SSVE. (I have a file on the file system which is named master and is in Nancy's default path convention for views - but I don't think it's the presence of the file which is causing the issue)
Is there a better approach to rendering a Nancy view from markdown which is not located on the file system? (yet maintain a file system provider for other routes)

Related

Nancyfx localization

I'm testing localization in Nancy and able to get it to work using EMBEDDED resource files but the issue is I don't want embedded resource files because I want them to be allowed to be edited via the GUI or using the file (if I go the DB route or setting the resource file as "content").
According to the doucmentation you should be able to override it to support using a database but I'm unable to get this to work (https://github.com/NancyFx/Nancy/wiki/Localization):
public class ResourceManager : ResourceBasedTextResource
{
public ResourceManager(IResourceAssemblyProvider resourceAssemblyProvider) : base(resourceAssemblyProvider)
{
}
public new string this[string key, NancyContext context]
{
get
{
return "HELO!";
}
}
}
This was just me messing around but I was hoping in the Razor view when I did #Text.Localization. it should return "HELO!" for everything... however it is not working
There really isn't a question in your post so I'm going to have to guess a bit and assume that you're not getting any exception but rather you're not seeing the "HELO!" in your view
Simply implementing a new ResourceBasedTextResource class is not enough. This is a core component and as such you are going to explicitly have to tell Nancy to use it. You do this by overriding the InternalConfiguration property of your Bootstrapper and tell Nancy to use your implementation instead
You can see it in the DemoBootstrapper of the demo that is linked from that wiki page https://github.com/NancyFx/Nancy/blob/8970ac9d6c7cf46e6060f0b83117c19fa18085c2/src/Nancy.Demo.Razor.Localization/DemoBootstrapper.cs#L11
Also, if you are not going to use resource files, then you should look into inheriting from ITextResource interface instead. It's a simple interface so it should be straight forward.
HTH

How can I get AngularJS working with the ServiceStack FallbackRoute attribute to support HTML5 pushstate Urls?

I am building a client/server solution, using an AngularJS Single Page App as the client component and a Self-Host ServiceStack RESTful API as the server component. A single Visual Studio Console Application Project holds HTML and JavaScript files for the AngularJS component, along with C# classes for bootstrapping the ServiceStack AppHost (I have devolved Interface and Service responsibilities to separate Visual Studio Projects).
I have set all HTML and JavaScript files to have a 'Build Action' of 'None' and a 'Copy to Output Directory' of 'Copy if newer'.
Everything is working very well as long as I am prepared to put up with having a '#' in my site URLs. I would like to eliminate this by using HTML5 pushstate URLs.
Effectively this means I need to persuade ServiceStack to serve up my default Single Page App HTML shell page whenever a non-existent route is requested. There is now a FallbackRoute attribute available in ServiceStack which appears to have been added exactly for this purpose.
However, I am unsure how to use it. I have found people asking similar questions here, here and here. But the answers given were all before the new FallbackRoute attribute arrived.
Essentially, I am looking for a simple, yet complete example of how to use the FallbackRoute attribute to ensure any requests to non-existent routes are redirected to a single static HTML page.
The RazorRockstars.Web has an implementation. I'll modify it to use a wildcard path and a default view:
[FallbackRoute("/{Path*}")]
public class Fallback
{
public string Path { get; set; }
public string PathInfo { get; set; }
}
public class RockstarsService : Service
{
[DefaultView("Index")]
public object Any(Fallback request)
{
request.PathInfo = base.Request.PathInfo;
return request;
}
// ...
}
Since this is a service it requires a View page (details here) rather than a content page.
In the RockStars example, I can't determine what view would be rendered for the FallBackResponse, but setting the view explicitly should be all you need.
The [DefaultView("Index")] attribute I added to the Any method maps the response to a Views/Index.cshtml file. The Index.cshtml file can be empty but for a template declaration, and the complete markup for your single page app can be in your template file (i.e. _Layout.cshtml)
Without Razor
Read the html into a string and return it, while setting the content type to "text/html" with an attribute, see wiki docs on service return types
public class RockstarsService : Service
{
static string readContents;
[AddHeader(ContentType = "text/html")]
public string Any(Fallback request)
{
// check timestamp for changes for production use
if (readContents == '') {
using (StreamReader streamReader = new StreamReader(pathFromConfigFile, Encoding.UTF8))
{
readContents = streamReader.ReadToEnd();
}
}
return readContents;
}
// ...
}
It turns out it is all very simple with the FallbackRoute functionality, once you work out how to use it properly:
[FallbackRoute("/{Path*}")]
public class Fallback
{
public string Path { get; set; }
}
public class FallBackService : Service
{
public object Any(Fallback request)
{
return new HttpResult(new FileInfo("index.html")) {ContentType = "text/html"};
}
}
Once this is in place, I find 'index.html' is indeed getting served up whenever I try to hit a non-existent route.
Any static files, such as JavaScript and CSS resources, get served up as normal (as long as they have a 'Copy to Output Directory' setting of 'Copy if newer', of course).
This works like a charm with the HTML5 Push-state functionality in AngularJS.

Create a directory dynamically inside the "web pages" folder of a java web application

So I'm trying to dynamically create a folder inside the web pages folder.
I'm making a game database. Everytime a game is added I do this:
public void addGame(Game game) throws DatabaseException {
em.getTransaction().begin();
em.persist(game);
em.getTransaction().commit();
File file = new File("C:\\GameDatabaseTestFolder");
file.mkdir();
}
So everything works here.
The file get's created.
But I want to create the folder like this:
public void addGame(Game game) throws DatabaseException {
em.getTransaction().begin();
em.persist(game);
em.getTransaction().commit();
File file = new File(game.getId()+"/screenshots");
file.mkdir();
}
Or something like that. So it will be created where my jsp files are and it will have the id off the game.
I don't understand where the folder is created by default.
thank you in advance,
David
It's by default relative to the "current working directory", i.e. the directory which is currently open at the moment the Java Runtime Environment has started the server. That may be for example /path/to/tomcat/bin, or /path/to/eclipse/workspace/project, etc, depending on how the server is started.
You should now realize that this condition is not controllable from inside the web application.
You also don't want to store it in the expanded WAR folder (there where your JSPs are), because any changes will get lost whenever you redeploy the WAR (with the very simple reason that those files are not contained in the original WAR).
Rather use an absolute path instead. E.g.
String gameWorkFolder = "/path/to/game/work/folder";
new File(gameWorkFolder, game.getId()+"/screenshots");
You can make it configureable by supplying it as a properties file setting or a VM argument.
See also:
Image Upload and Display in JSP
getResourceAsStream() vs FileInputStream

Silverlight: Business Application Needs Access To Files To Print and Move

I have the following requirement for a business application:
(All of this could be on local or server)
Allow user to select folder location
Show contents of folder
Print selected items from folder (*.pdf)
Display which files have been printed
Potentially move printed files to new location (sub-folder of printed)
How can I make this happen in Silverlight?
Kind regards,
ribald
First of all, all but the last item can be done (the way you expect). Due to security protocols, silverlight cannot access the user's drive and manipulate it. The closest you can get is accessing silverlight's application storage which will be of no help to you whatsoever in this case. I will highlight how to do the first 4 items.
Allow user to select folder location & Show contents of folder
public void OnSelectPDF(object sender)
{
//create the open file dialog
OpenFileDialog ofg = new OpenFileDialog();
//filter to show only pdf files
ofg.Filter = "PDF Files|*.pdf";
ofg.ShowDialog();
byte[] _import_file = new byte[0];
//once a file is selected proceed
if (!object.ReferenceEquals(ofg.File, null))
{
try
{
fs = ofg.File.OpenRead();
_import_file = new byte[fs.Length];
fs.Read(_import_file, 0, (int)fs.Length);
}
catch (Exception ex)
{
}
finally
{
if (!object.ReferenceEquals(fs, null))
fs.Close();
}
//do stuff with file - such as upload the file to the server
};
}
If you noticed, in my example, once the file is retrieved, i suggest uploading it to a webserver or somewhere with temporary public access. I would recommend doing this via a web service. E.g
//configure the system file (customn class)
TSystemFile objFile = new TNetworkFile().Initialize();
//get the file description from the Open File Dialog (ofg)
objFile.Description = ofg.File.Extension.Contains(".") ? ofg.File.Extension : "." + ofg.File.Extension;
objFile.FileData = _import_file;
objFile.FileName = ofg.File.Name;
//upload the file
MasterService.ToolingInterface.UploadTemporaryFileAsync(objFile);
Once this file is uploaded, on the async result, most likely returning the temporary file name and upload location, I would foward the call to some javascript method in the browser for it to use the generic "download.aspx?fileName=givenFileName" technique to force a download on the users system which would take care of both saving to a new location and printing. Which is what your are seeking.
Example of the javascript technique (remember to include System.Windows.Browser):
public void OnInvokeDownload(string _destination)
{
//call the browser method/jquery method
//(I use constants to centralize the names of the respective browser methods)
try
{
HtmlWindow window = HtmlPage.Window;
//where BM_INVOKE_DOWNLOAD is something like "invokeDownload"
window.Invoke(Constants.TBrowserMethods.BM_INVOKE_DOWNLOAD, new object[] { _destination});
}
catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex.ToString()); }
}
Ensure you have the javascript method existing either in an included javaScript file or in the same hosting page as your silverlight app. E.g:
function invokeDownload(_destination) {
//some fancy jquery or just the traditional document.location change here
//open a popup window to http://www.myurl.com/downloads/download.aspx? fileName=_destination
}
The code for download.aspx is outside the scope of my answer, as it varies per need and would just lengthen this post (A LOT MORE). But from what I've given, it will "work" for what you're looking for, but maybe not in exactly the way you expected. However, remember that this is primarily due to silverlight restrictions. What this approach does is rather than forcing you to need a pluging to view pdf files in your app, it allows the user computer to play it's part by using the existing adobe pdf reader. In silverlight, most printing, at least to my knowledge is done my using what you call and "ImageVisual" which is a UIElement. To print a pdf directly from silverlight, you need to either be viewing that PDF in a silverlight control, or ask a web service to render the PDF as an image and then place that image in a control. Only then could you print directly. I presented this approach as a lot more clean and direct approach.
One note - with the temp directory, i would recommend doing a clean up by some timespan of the files on the server side everytime a file is being added. Saves you the work of running some task periodically to check the folder and remove old files. ;)

Will Prism OnDemand module loading work in an OOB scenerio?

Should the loading of OnDemand Prism modules work in an OOB scenerio? If so, I cannot seem to make it work. Everything is currently working in browser without any problems. Specifically I:
register my modules in code:
protected override IModuleCatalog GetModuleCatalog() {
var catalog = new ModuleCatalog();
Uri source;
if( Application.Current.IsRunningOutOfBrowser ) {
source = IsolatedStorageSettings.ApplicationSettings[SOURCEURI] as Uri;
}
else {
var src = Application.Current.Host.Source.ToString();
src = src.Substring( 0, src.LastIndexOf( '/' ) + 1 );
source = new Uri( src );
IsolatedStorageSettings.ApplicationSettings[SOURCEURI] = source;
IsolatedStorageSettings.ApplicationSettings.Save();
}
if( source != null ) {
var mod2 = new ModuleInfo { InitializationMode = InitializationMode.OnDemand,
ModuleName = ModuleNames.mod2,
ModuleType = "mod2.Module, mod2.Directory, '1.0.0.0', Culture=neutral, PublicKeyToken=null" ),
Ref = ( new Uri( source, "mod2.xap" )).AbsoluteUri };
catalog.AddModule( mod2 );
}
// per Jeremy Likeness - did not help.
Application.Current.RootVisual = new Grid();
return ( catalog );
}
later request for the module to be loaded is made:
mModuleManager.LoadModule( ModuleNames.mod2 );
and wait for a response to an event published during the initialization of that loaded module.
The module appears to never be loaded, and when the application is running under the debugger there will be a message box that states that the web server returned a 'not found' error. I can take the requesting url for the module and enter it into Firefox and download the module with no problem.
I have not been able to find any reference to this actually being workable, but it seems as though it should. The most I have found on the subject is a blog entry by Jeremy Likeness, which covers loading modules in MEF, but applying his knowledge here did not help.
The server is localhost (I have heard it mentioned that this might cause problems). The server has a clientaccesspolicy.xml file - although I don't expect that is needed.
I am using the client stack and register it during app construction:
WebRequest.RegisterPrefix( Current.Host.Source.GetComponents( UriComponents.SchemeAndServer, UriFormat.UriEscaped ), WebRequestCreator.ClientHttp );
Followup questions:
Can all of the xaps be installed to the client desktop in some manner - or only the main application xap? specify them in appmanifest.xml somehow??
Is it worth it make this work if only the application.xap is installed and the rest of the xaps must be downloaded anyway?
Once I worked on a similar scenario. The trick is having the modules stored in isolated storage and use a module loader that reads from isolated storage when working offline.
This is because otherwise, you can't get download the modules that are in a different .xap file than the Shell.
Thanks,
Damian
It is possible to hook custom module loaders into Prism if you're willing to tweak the Prism source and build it yourself. I was actually able to get this to work pretty easily - in our app, I look on disk first for the module, and if it's not found, I fall back to loading it from the server via a third-party commercial HTTP stack that supports client certificates.
To do this, download the Prism source code, and locate the Microsoft.Practices.Composite.Modularity.XapModuleTypeLoader class. This class uses another Prism class, Microsoft.Practices.Composite.Modularity.FileDownloader, to download the .xap content; but it instantiates it directly, giving you no chance to inject your own or whatever.
So - in XapModuleTypeLoader, I added a static property to set the type of the downloader:
public static Type DownloaderType { get; set; }
Then I modified the CreateDownloader() method to use the type specified above in preference to the default one:
protected virtual IFileDownloader CreateDownloader() {
if (_downloader == null) {
if (DownloaderType == null) {
_downloader = new FileDownloader();
} else {
_downloader = (IFileDownloader)Activator.CreateInstance(DownloaderType);
}
}
return _downloader;
}
When my app starts up, I set the property to my own downloader type:
XapModuleTypeLoader.DownloaderType = typeof(LocalFileDownloader);
Voila - now Prism calls your code to load its modules.
I can send you my LocalFileDownloader class as well as the class it falls back to to load the .xap from the web if you're interested... I suspect though that if you look at Prism's FileDownloader class you'll see that it's simple enough.
With regard to your other questions, the clientaccesspolicy.xml file is probably not needed if the URL the app is installed under is the same one you're talking to, or if you're in elevated trust.
The .xaps can definitely be pre-installed on the client, but it's a bit of work. What we did was write a launcher app that is a standalone .NET 2.0 desktop app. It downloads the main .xap plus certain modules* (checking for updates and downloading only as needed), then uninstalls/reinstalls the app if necessary, then launches the app. The last two are done via sllauncher.exe, which is installed as part of Silverlight. Here's a good intro to that: http://timheuer.com/blog/archive/2010/03/25/using-sllauncher-for-silent-install-silverlight-application.aspx.
Assuming you're running under elevated trust, it should also be possible to pre-fetch the module .xaps from within the SL client, but before they're actually requested due to user action. You'd just need to put them in a folder under My Documents somewhere, and then use the custom module loading approach described above to pull them from there.
*In our case, our main .xap is 2/3 of the application. The rest of our .xaps are small, so we download them on-the-fly, with the exception of some .xaps we created as containers for third-party components. We don't expect to update those very often, so we pre-install them.

Resources