I have an asp.net core 2 webapi service. I want to read appsettings.json but I cannot figure it out. As usual, when I search the internet I get a dozen completely different answers based on various versions of the framework that ultimately don't seem to work.
As an example appsettings.json:
"AppSettings": {
"Domain": "http://localhost"
}
Firstly I tried this:
Added via nuget Microsoft.Extensions.Configuration and Microsoft.Extensions.Configuration.Json
In my ConfigureServices method I added:
services.AddSingleton<IConfiguration>(Configuration);
In my Controller I injected the config:
IConfiguration iconfig;
public ValuesController(IConfiguration iConfig)
{
iconfig = iConfig;
}
To retrieve it:
return "value: " + iconfig.GetValue<string>("AppSettings:Domain");
I can see the controller constructor being called and passing in a config, but the value is always null.
I did notice that Startup already passes in an IConfiguration. Is it a case of yet another change in implementation and i need to do something different?
[edit]
I've now read
https://joonasw.net/view/aspnet-core-2-configuration-changes
Which says it's all change again and it's auto injected, but after following the code it doesn't actually say how you get your hands on the data in your controller.
You can take a look at my answer here: https://stackoverflow.com/a/46940811/2410655
Basically you create a class that matches the properties you define in appsettings.json file (In the answer it's the AppSettings class).
And then in ConfigureServices(), you inject that class using services.Configure<>. That class will be available in all Controllers by DI.
To access its data, you can take a look at #aman's original question post from the link above.
public class HomeController : Controller
{
private readonly AppSettings _mySettings;
public HomeController(IOptions<AppSettings> appSettingsAccessor)
{
_mySettings = appSettingsAccessor.Value;
}
}
Related
My issue is similar to Web Api Routing : Multiple controller types were found that match the URL but I want to keep them in separate controllers.
From the comments, 2 preexisting answers are good workarounds but do not solve the actual issue I'm trying to resolve.
The URLs I'm making up are similar to nested directories in a file system OR are very similar to Firebase URLs.
/BiggestSet/{BiggestSetCode}/Subset1/{Subset1Code}/SubsetOfSubset1/{SubsetOfSubset1}
... etc all the way down to where ever the tree stops. Think of it as a tree of data.
/Collection/{Instance}/Collection/{Instance}
The issue I have is that at the /Collection level I want to also provide specific collection level operations. Like Add and search and other collection specific Operations Collection/ProccessData
Collection Controller:
/Collection/Add
/Collection/ProcessDataOnTheColleciton
Instance Controller:
/Collection/{InstanceCode}
/Collection/{InstanceCode}/ProcessOnTheInstance
The problem I'm having is the Collection/ProcessData clashes with the instance Collection/{InstanceCode}
NOTE: 1 is an parameter and the other is a constant.
If you setup the controllers so that collection and Instance are in the same controller. the /{InstanceCode} doesn't clash with the /ProcessData
BUT
If you setup so the controllers are split into logical functions WebAPI gives the error Multiple controller types were found that match the URL.
Does anyone know how to modify attribute routing to somehow behave as if they are in the same controller OR to prioritize the constant over the parameter across controllers?
To keep two separate controllers and still have such routes you can use regular expression route constraints. This way you can specify for the instanceCode you accept everything except the actions from the other controller.
Here is a sample of how to configure routes like that:
public class CollectionController : ApiController
{
[HttpGet]
[Route("Collection/Add")]
public string Add()
{
return $"CollectionController = Collection/Add";
}
[HttpGet]
[Route("Collection/Process")]
public string Process()
{
return $"CollectionController = Collection/Process";
}
}
public class InstanceController : ApiController
{
[HttpGet]
[Route("Collection/{instanceCode:regex(^(?!Add$|Process$).*)}")]
public string Get(string instanceCode)
{
return $"InstanceController = Collection/{instanceCode}";
}
[HttpGet]
[Route("Collection/{instanceCode:regex(^(?!Add$|Process$).*)}/Process")]
public string Process(string instanceCode)
{
return $"InstanceController = Collection/{instanceCode}/Process";
}
}
Here is also a link to the post that explains the regular expression used in the sample.
An even better option would be if you have a specific format for the instanceCode and set the regular expression to accept only this specific format. Then you would not need to modify the regular expression for every new action added. I include also a link to the documentation for all available Route constraints. There you can see all the available options. For example if your instance code is a number you don't even need a regular expression you can just restrict with the int constraint like this [Route("Collection/{instanceCode:int}")].
I want to provide access to a legacy database to customers via a REST API using ASP.NET 5 / MVC6.
There seem to be many examples for writing controllers for single entities but what I don't find is some guideline on how to write controllers for related entities.
In my domain model there are f.e. two entity classes:
Device
MeasuringPoint
and each device can have 1..N measuring points.
I want my controllers to have only Get actions, that is, the API is read-only.
For the Device entity I would use
public class DevicesController : Controller
{
// GET: api/devices
[HttpGet]
public IEnumerable<Device> Get()
{
//retrieve all devices
}
...
}
The next step would usually be for a user to query all measuring points for a specific (selected) device.
How would I write that controller action?
What is the recommended routing and how would I set that up?
For the client side I found suggestions like:
get api/devices/{ID}/measuringPoints
but I have no idea how this is implemented.
You can use attribute routing to achieve what you want.
If you have enabled MVC in your Startup class using app.UseMvc(), then you already have support for routing via the RouteAttribute.
[Route("api/[controller]")]
public class DevicesController : Controller {
// GET: api/devices
[HttpGet]
[Route("")]
public IEnumerable<Device> Get() {...}
...
// GET: api/devices/5/measuringPoints
[HttpGet]
[Route("{id}/measuringPoints")]
public IEnumerable<MeasuringPoint> GetMeasuringPoint(int id) {...}
}
I am trying to standardize an extension model for our REST API development team. We need to provide default implementation of routes, while allowing for custom implementations of routes that replace the default as well.
As a simple example if we have a GET route api/users like this:
public class DefaultUsersController : ApiController
{
[HttpGet]
[Route("api/users", Order = 0)]
public IEnumerable<string> DefaultGetUsers()
{
return new List<string>
{
"DefaultUser1",
"DefaultUser2"
};
}
}
We expect the default work like this:
Now a developer wants to change the behavior of that route, he should be able to simply define the same route with some mechanism to imply their implementation should be the one used, instead of the default. My initial thinking was to use the Order property on the Route attribute since that's what it appears to be there for, as a way to provide a priority (in ascending order) when an ambiguous route is discovered. However it's not working that way, consider this custom implementation that we want to override the default api/users route:
public class CustomUsersController : ApiController
{
[HttpGet]
[Route("api/users", Order = -1)]
public IEnumerable<string> CustomGetUsers()
{
return new List<string>
{
"CustomUser1",
"CustomUser2"
};
}
}
Notice the Order property is set to -1 to give it a lower priority value than the default, which is set to 0. I would have thought this would be used by the DefaultHttpControllerSelector, but it isn't. From the DefaultHttpControllerSelector:
And we end up with this exception being returned in the response:
Is it possible Microsoft just missed the logic/requirement to use Order as a route disambiguator and this is a bug? Or is there another simple way to override a route, hopefully with an attribute?
I have pretty much the same problem. I am creating a starter site, but I want users to be able to redefine to behaviour of a Controller, especially if there is a bug.
I use Autofac to resolve the Controller, but even when I register the new controller as the old one, the original one gets selected.
What I'll do is probably go with URL Rewriting. Especially since this issue is temporary in my case. However, I would be interested if someone has a better option.
In standard MVC I use JsonNet to return JSON that is in camelCase and sucessfully serializes entities that have related entities (which otherwise reports a "cycles" error" using the default serializer).
I'd like to do the same for a WebAPI controller in an Orchard module. By default it returns PascalCase JSON and reports a "cyles" exception when given a list of entities.
Can anyone explain how best to configure the JSON output from within the Orchard module, to mimic what JsonNet would produce?
I've found a workaround, which is to set the JSON formatters settings to camelCase in an ActionFilter:
public class CamelCaseJsonAttribute : ActionFilterAttribute {
public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext)
{
var jsonFormatter = actionContext.ControllerContext.Configuration.Formatters.OfType<JsonMediaTypeFormatter>().First();
jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
}
}
But this seems inefficient, as it gets set on each request, rather than globally, once.
I'm guessing there is an extensibility point somewhere in a module to set the HttpConfiguration - can anyone tell me one way or the other?
Many thanks.
I have opened up a question on CodePlex but have not received any responses at all.
Basically, I have a base controller that all of my controllers inherit from. When I create a new MVC3 project, put my controllers in another assembly, and add MEFContrib.MVC3 to the project, everything works great. When I make any of the controllers inherit from my base class, they can no longer be found.
I am not familiar enough with MEFContrib to know what exactly is breaking, but I have tried to decorate my controllers with ExportAttributes and that has not worked, either.
All of this is a different assembly than the main MVC project:
public class MyBaseController : Controller
{
...
}
// This controller cannot be found.
public class HomeController : MyBaseController
{
public ActionResult Index ()
{
// Do Stuff
return View ();
}
}
// This controller can be found.
public class HomeController : Controller
{
// yada, yada, yada...
}
Edit:
counsellorben was exactly right. I had dependencies that were not properly marked for export and so the controllers could not be properly composed. I stepped through each of my dependencies, stepping through their own dependencies, and found the few I missed.
The most likely issue is that there is a problem with a dependency in your MyController class. This will cause a problem with any controller inheriting from MyController.
Please see this answer for some sample code you can use to try and diagnose where your problem lies.
I think you need to decorate with the InheritedExport attribute.