Can the ServiceStack config setting "WebHostPhysicalPath" be used for relative paths? - servicestack

Hello ServiceStack aficionados!
I would like to host static XML files through the ServiceStack service; however, I can't seem to get the configuration right and only receive 404 errors. Feels like I tried all sorts of path/url combinations.
Can the WebHostPhysicalPath be defined as a relative path? Is there another setting that must be enabled? I was concerned that maybe the XML extension is conflicting with the format conversion stuff.
Also, can I host Razor cshtml files this way too?
Any comments on this approach?
thanks!

You can return a static file from a service like so:
[Route("/myFile/")]
public class GetMyFile
{
}
public class HelloService : Service
{
public HttpResult Any(GetMyFile request)
{
return new HttpResult(new FileInfo("~/myfile.xml"), asAttachment:true) { ContentType = "text/xml" };
}
}
As for razor: http://razor.servicestack.net/

Related

Get Azure AppSettings in a Controller

I have an ASP.NET Core 2 application hosted on Azure, and I added a new Application Settings MyNewSetting for my App in the Azure Portal.
How do I access that setting from a controller?
My code bellow:
public void ConfigureServices(IServiceCollection services)
{
services.AddOptions();
services.Configure<AppSecrets>(Configuration);
services.AddSingleton<ITableRepositories, TableClientOperationsService>();
//...
My Controller:
public class RecordController : Controller
{
const int MyNewSetting = 7; // this one to replace with Azure Setting one
private readonly ITableRepositories repository;
public RecordController(ITableRepositories rep) {
repository = rep;
}
Here, I need probably to add FromServices injection, but I am not sure if it will work...
EDIT:
Folowing the #dee_zg answer, the following code could probably do the job:
public class RecordController : Controller
{
int MyNewSetting = 7;
private readonly ITableRepositories repository;
public RecordController(ITableRepositories rep) {
repository = rep;
int myInt;
if (int.TryParse(System.Environment.GetEnvironmentVariable("MY_NEW_SETTING"),
out myInt)) {
MyNewSetting = myInt;
};
}
You can choose to either get them from AppSettings["your-key"] collection or as environment variables: Environment.GetEnvironmentVariable("your-key").
From there you can map them to your custom IOptions and inject wherever you need them.
There's quite a few things you can do.
Use Options and configuration objects
The options pattern uses custom options classes to represent a group of related settings. We recommended that you create decoupled classes for each feature within your app.
Use an IOptionsSnapshot.
IOptionsSnapshot supports reloading configuration data when the configuration file has changed. It has minimal overhead. Using IOptionsSnapshot with reloadOnChange: true, the options are bound to Configuration and reloaded when changed.
... (see documentation)
In short, have a look at Configuration in ASP.NET Core, determine the scenario that best fits your needs and have at it!
Hope this helps.

Is there a way to remove the "/json/reply/" section of the url?

I would like the URL for a request to be /AmazingRequest (or even /AmazingService) instead of /json/reply/AmazingRequest.
I've tried the Route attribute, but it seems to have no effect. Is it possible within ServiceStack, or would I have to resort to URL rewriting?
This is what I've tried. It compiles, but the attribute has no effect.
public class MyServiceEndpoints : IService
{
[Route("/AmazingService")]
public AmazingResponse Post(AmazingRequest request)
{
return new Amazing(request).GetResponse();
}
}
I realize I would need to tell ServiceStack that it is a json request, but I'm fine with adding the Accept and Content-Type headers or maybe even a ?format=json to the query string.
P.S. I'm using the BSD version of ServiceStack
In ServiceStack Routes are defined on the Request DTO as it's part of your Service Contract, e.g:
[Route("/AmazingService")]
public class AmazingRequest { ... }
The pre-defined Route you're using is because ServiceStack doesn't think there's any custom route defined for your Service and just uses the default one.
The alternative way for declaring your Routes is to use the Fluent Registration API in your AppHost, e.g:
public void Configure(Container container)
{
Routes
.Add<AmazingRequest>("/AmazingService");
}
But the benefit of defining them on the Request DTO's is that your .NET Service Clients will also have access to them and will be able to use your custom routes instead of falling back to the pre-defined routes.

Serving static files in ASP.NET 5 MVC 6

My wwwroot static files aren't being resolved.
I understand that to serve static files, I need to put them in wwwroot:
favicon.ico resolves just fine, but schema/v1-0.json does not. I get the generic message:
The resource you are looking for has been removed, had its name
changed, or is temporarily unavailable.
I have the following wired up in Startup:
app.UseMiddleware<StaticFileMiddleware>(new StaticFileOptions());
app.UseStaticFiles();
I am using DNX beta6. The above require beta5 packages. I cannot find anything online regarding serving static files in beta6. I am not sure if this could be the cause of the problem.
EDIT:
As per Sirwan's answer, I have added the following, but the json file is still not available:
var options = new StaticFileOptions
{
ContentTypeProvider = new JsonContentTypeProvider(),
ServeUnknownFileTypes = true,
DefaultContentType = "application/json"
};
app.UseStaticFiles(options);
The JsonContentTypeProvider class:
public class JsonContentTypeProvider : FileExtensionContentTypeProvider
{
public JsonContentTypeProvider()
{
Mappings.Add(".json", "application/json");
}
}
I can even see the file when browsing the server:
Try this:
app.UseStaticFiles(new StaticFileOptions
{
ServeUnknownFileTypes = true,
DefaultContentType = "image/x-icon"
});
If you have multiple file types that are unknown to ASP.NET you can use FileExtensionContentTypeProvider class:
var provider = new FileExtensionContentTypeProvider();
provider.Mappings.Add(".json", "application/json");
provider.Mappings.Add(".ico", "image/x-icon");
// Serve static files.
app.UseStaticFiles(new StaticFileOptions { ContentTypeProvider = provider });
If you're using IIS, make sure you've added the correct mime-type mappings if you don't have a catch-all managed handler. Even though you don't need web.config for your website to work, IIS will still use that for your website.
Someone correct me if I'm wrong, but I believe that if you have not configured IIS to use a managed handler to serve static files it will still default to StaticFileModule and calling app.UseStaticFiles doesn't actually do anything. If you run it using dnx, however, then app.UseStaticFiles gets used.
Just a side note, you should probably also upgrade to beta7 if you haven't already.

Azure Mobile Services - No bootstrapper found

I have a Azure Mobile Services project. When running locally everything works fine, the Application_Start() method gets called which in turn calls my WebApiConfig.Register() method.
However, when published to a live Azure Mobile Services server the Application_Start() does not get called along with the WebApiConfig.Register().
In the servers log I have the following entry:
No bootstrapper found -- using default bootstrapper. A bootstrapper can be specified in one of two ways: Either by defining a public, static class with name 'WebApiConfig' having a public parameter-less member called 'Register', or using the 'IBootstrapper' attribute to define a public class with a default constructor.
Why is Azure Mobile Services not picking up my BootStrapping WebApiConfig?
public static class WebApiConfig
{
public static void Register()
{
Trace.TraceInformation("Hello from WebApiConfig Register().");
// Use this class to set configuration options for your mobile service
ConfigOptions options = new ConfigOptions();
// Use this class to set WebAPI configuration options
HttpConfiguration config = ServiceConfig.Initialize(new ConfigBuilder(options));
// To display errors in the browser during development, uncomment the following
// line. Comment it out again when you deploy your service for production use.
// config.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
}
}
public class WebApiApplication : System.Web.HttpApplication
{
public WebApiApplication()
{
Trace.TraceInformation("Hello from WebApiApplication ctor!");
}
protected void Application_Start()
{
Trace.TraceInformation("Hello from Application_Start()");
//RouteConfig.RegisterRoutes(RouteTable.Routes);
WebApiConfig.Register();
var dataContext = new DataContext();
dataContext.Database.Initialize(false);
}
}
Help is much appreciated!
That is bizarre... It really looks like you got it right. After working with .net backend azure mobile service for few weeks, I might suggest just maybe restart the service in portal and republish. I have hit some weird unexplained stuff just like you are and somehow fix like that.

Reading a file from a UNC path and setting the correct MIME type in a HTTP request

How would I go about reading a file from a UNC path, discovering the proper MIME type, and streaming that out to a browser?
It feels to me like I'm re-inventing IIS, and I'll also have to maintain my own MIME type database for each file extension. Does the above request sound reasonable, or is there a better way?
I plan on streaming this out via a browser HTTP Get request on IIS7. If it matters, I'm also running Cognos on the same server. Any framework is OK (WCF, ASPX, etc)
Using WCF its pretty basic:
This code can be hosted under IIS/Service/WAS/etc.
I never found a convenient way to handle the mime type, you will need to have your own db that will map file extension into mime types.
[ServiceContract(SessionMode = SessionMode.NotAllowed)]
public interface IMediaRetriver
{
[OperationContract]
[WebGet(UriTemplate = "/get?f={fileName}")]
Stream Get(string fileName);
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class MediaRetriver : IMediaRetriver
{
public Stream Get(string fileName)
{
// pro tips
// this will cause the file dialog to show the file name instead of "get"
WebOperationContext.Current.OutgoingResponse.Headers.Add(
"Content-disposition", string.Format("inline; filename={0}", fileName));
WebOperationContext.Current.OutgoingResponse.ContentType =
"application/octet-stream";
// you want to add sharing here also
return File.Open(fileName)
}
}

Resources