I have a web api in Nancy 1.4.3. I have defined some settings in web.config under applicationSettings section. I was wondering how can I read these settings in a Nancy module (or Bootstrapper)? Because the conventional ways of reading these settings as in MVC/WebAPI are not available in Nancy.
Please consider that I am using Nancy 1.4.3 not Nancy 2x and .net 4.6.1 not .net core.
For simplicity, I am writing how the applicationSettings section looks like in web.config:
<applicationSettings>
<Applicaton1.Properties.Settings>
<setting name="DefaultUserID" serializeAs="String">
<value>BatchReader</value>
</setting>
<setting name="DefaultPaymentFrequencyCode" serializeAs="String">
<value>0</value>
</setting>
<setting name="DefaultPaymentTypeCode" serializeAs="String">
<value>1</value>
</setting>
</Application1.Properties.Settings>
You should be able to read it exactly the same as any asp.net app.
Make sure you add reference to:
System.Configuration
In Web.config add your key:
<appSettings>
<add key="key" value="hello key" />
</appSettings>
Include System.Configuration in your Bootstrapper:
namespace Test
{
using System.Configuration;
using Nancy;
using Nancy.Authentication.Forms;
using Nancy.Bootstrapper;
using Nancy.TinyIoc;
public class Bootstrapper : DefaultNancyBootstrapper
{
protected override void ApplicationStartup (TinyIoCContainer container,
IPipelines pipelines)
{
base.ApplicationStartup (container, pipelines);
StaticConfiguration.DisableErrorTraces = false;
StaticConfiguration.EnableRequestTracing = true;
}
protected override void ConfigureApplicationContainer (TinyIoCContainer
container)
{
base.ConfigureApplicationContainer (container);
var key = ConfigurationManager
.AppSettings.Get ("key")
}
protected override void ConfigureRequestContainer (TinyIoCContainer container,
NancyContext context)
{
base.ConfigureRequestContainer (container, context);
}
protected override void RequestStartup (TinyIoCContainer container,
IPipelines pipelines,
NancyContext context)
{
base.RequestStartup (container, pipelines, context);
}
}
}
Thats it! :)
What conventional ways would you use in WebApi that are missing in Nancy ?
For a web app I think you should really be using System.Web.Configuration:
using System.Web.Configuration
For example:
var someVar = WebConfigurationManager.AppSettings["SomeSetting"];
See here for more information.
Related
I have a .NET Framework 4.6.1 solution which has this global.asax.cs:
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{ Microsoft.ApplicationInsights.Extensibility.TelemetryConfiguration.Active.InstrumentationKey = EnvironmentHelper.InstrumentationKey;
HttpConfiguration config = GlobalConfiguration.Configuration;
GlobalConfiguration.Configure(WebApiConfig.Register);
}
protected void Application_Error(Object sender, EventArgs e)
{
_telemetry.TrackException(Server.GetLastError());
}
}
This WebApiConfig.cs:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
config.Services.Add(typeof(IExceptionLogger), new InsightsExceptionLogger());
}
}
This logger class:
public class InsightsExceptionLogger : ExceptionLogger
{
public override void Log(ExceptionLoggerContext context)
{
if (context != null && context.Exception != null)
{
var ai = new TelemetryClient();
ai.TrackException(context.Exception);
}
base.Log(context);
}
}
And this is an example of a controller and method:
public class SomeController : ApiController
{
[HttpPost, Route("api/v1/Something")]
public async Task<IHttpActionResult> Something()
{
The problem is I'm not getting any requests logged in Insights at all.
What do I need to do to get these API calls logged in Insights? (Assuming that simply adding .TrackRequest() is not necessary.)
Create a Request Telemetry initializer class and add the below code. On request Telemetry property you can select which property u want to add in a application insights.
After the Request Telemetry initializer class created add
<Add Type="webapptostoreloginappinsights.ReqTelemetryInitializer,webapptostoreloginappinsights"/>
in a applicationinsights.config file under telemetry processors
Make sure to call the request Telemetry initializer class in a global.asax.cs
Try to run the code now able to view the api request in a Application Insights
What I ended up doing was this....
Add packages:
<package id="Microsoft.ApplicationInsights" version="2.18.0" targetFramework="net472" />
<package id="Microsoft.ApplicationInsights.Agent.Intercept" version="2.4.0" targetFramework="net472" />
<package id="Microsoft.ApplicationInsights.DependencyCollector" version="2.18.0" targetFramework="net472" />
<package id="Microsoft.ApplicationInsights.PerfCounterCollector" version="2.18.0" targetFramework="net472" />
<package id="Microsoft.ApplicationInsights.Web" version="2.18.0" targetFramework="net472" />
<package id="Microsoft.ApplicationInsights.WindowsServer" version="2.18.0" targetFramework="net472" />
<package id="Microsoft.ApplicationInsights.WindowsServer.TelemetryChannel" version="2.18.0" targetFramework="net472" />
<package id="Microsoft.AspNet.TelemetryCorrelation" version="1.0.8" targetFramework="net472" />
Ensure web.config <system.web> contains this:
<httpModules>
<add name="TelemetryCorrelationHttpModule" type="Microsoft.AspNet.TelemetryCorrelation.TelemetryCorrelationHttpModule, Microsoft.AspNet.TelemetryCorrelation" />
<add name="ApplicationInsightsWebTracking" type="Microsoft.ApplicationInsights.Web.ApplicationInsightsHttpModule, Microsoft.AI.Web" />
</httpModules>
During the process the ApplicationInsights.config file was created and once deployed the application started logging Reuqest entries in Insights.
All of a sudden my app won't display a page and I now get "You do not have permission to view this directory or page." I looked at this but the suggestions there didn't help.
for my code:
[ServiceContract]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
// NOTE: If this class is renamed, remember to update the global.asax.cs file
public class Service
{
[WebGet(UriTemplate = "")]
public string GetTest()
{
return "Windward update REST service running.";
}
}
When I request an aspx page, it works.
Global.asx.cs:
public class Global : HttpApplication
{
private static readonly ILog log = LogManager.GetLogger(typeof(Global));
void Application_Start(object sender, EventArgs e)
{
RegisterRoutes();
log4net.Config.XmlConfigurator.Configure();
log.Info(string.Format("Update REST server started, running under user {0}", WindowsIdentity.GetCurrent().Name));
}
private void RegisterRoutes()
{
// The class providing the REST service
RouteTable.Routes.Add(new ServiceRoute("Service", new WebServiceHostFactory(), typeof(Service)));
}
web.config (relevant parts):
<system.web>
<compilation debug="true" targetFramework="4.5"/>
<pages controlRenderingCompatibilityVersion="4.0"/>
</system.web>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
<add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/>
</modules>
</system.webServer>
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
<standardEndpoints>
<webHttpEndpoint>
<!--
Configure the WCF REST service base address via the global.asax.cs file and the default endpoint
via the attributes on the <standardEndpoint> element below
-->
<standardEndpoint name="" helpEnabled="true" automaticFormatSelectionEnabled="true"/>
</webHttpEndpoint>
</standardEndpoints>
</system.serviceModel>
Nothing substantive has changed. So why do the requests no longer call the service?
thanks - dave
I made a custom handler for test purposes, which looks like:
namespace MVCHttpHandlerProject
{
public class SomeHandler : IHttpHandler
{
public bool IsReusable
{
get { return true; }
}
public void ProcessRequest(HttpContext context)
{
context.Response.Write("SomeHandler test");
}
}
}
Then I added to my web.config next lines:
<httpHandlers>
<add path="SomeHandler.axd" verb="*" type="MVCHttpHandlerProject.SomeHandler, MVCHttpHandlerProject" /></httpHandlers>
and in <system.webServer>
<handlers>
<add path="SomeHandler.axd" verb="*" type="MVCHttpHandlerProject.SomeHandler, MVCHttpHandlerProject" name="SomeHandler.axd"/>
</handlers>
My Global.asax.cs was not modified and looks exactly as when it was generated with routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); in RegisterRoutes method.
Still, when I try to get to "http://localhost/Home/SomeHandler.axd", "The resource cannot be found" error occurs. Why? Did I miss something? How should I fix this?
You should be requesting http://localhost/SomeHandler.axd instead of http://localhost/Home/SomeHandler.axd. There's no Home.
I have a problem with my Declarative Services. I have 2 bundles, one is a server provider and another the user interface that consumes the service.
On server side, the implementation is:
public boolean checkUser(){
return true;
}
And the XML file inside OSGi-INF folder:
<component name="ZBService">
<implementation class="service.ZBService" />
<service>
<provide interface="service.IZBService" />
</service>
</component>
On client side, the implementation is:
public class GreetingServiceImpl extends RemoteServiceServlet implements GreetingService{
IZBService zb;
public void setZBService(IZBService eventAdmin) {
this.zb = eventAdmin;
}
public void unsetZBService(IZBService eventAdmin){
if(this.zb == eventAdmin){
this.zb = null;}
}
public boolean greetServer(String input, String input2) throws Exception {
return zb.checkUser();
}
}
And XML file:
<component name="ZBService">
<implementation class="main.java.com.gwt.app.server.GreetingServiceImpl" />
<service>
<provide interface="main.java.com.gwt.app.client.GreetingService"/>
</service>
<reference name="zb" interface="service.IZBService" bind="setZBService" unbind="unsetZBService" cardinality="0..n" policy="dynamic" />
</component>
Also, I have included the tag Service-Component on manifest file and I have deployed the equinox ds bundle that is ACTIVE.
The client is a GWT user interface, then I inject the service reference into server side of GWT. Well, when I deploy the application on Equinox it runs, but when I push the button, I launch an event to call ZBService. I have debugged the application and the error is zb attribute is null. It is to say, the dependence is nos injected. However the services are exposed on Equinox. If I write services on Equinox console, the services are deployed. Then, my conclusion is the error is due to the injection does not perform.
I would like to know if someone knows what is the reason??
Thanks a lot in advance!!
Nice day
EDIT:
I did your suggestions but it doesn't run. I change the component names and condinality/policy. The result is the same --> NullPointerException due to the injection isn't done.
Also I have debug the application to see if the methods bind and/or unbind are called, but they aren't.
The complete class is:
public class GreetingServiceImpl extends RemoteServiceServlet implements GreetingService{
static protected IZBService zb;
public GreetingServiceImpl(){
System.out.println("Constructor GreetingServiceImpl");
}
public IZBService getZb() {
return zb;
}
public void setZb(IZBService zb) {
GreetingServiceImpl.zb = zb;
}
public void unsetZb(IZBService zb) {
GreetingServiceImpl.zb = zb;
}
#Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// Cache the current thread
Thread currentThread = Thread.currentThread();
// We are going to swap the class loader
ClassLoader oldContextClassLoader = currentThread.getContextClassLoader();
currentThread.setContextClassLoader(this.getClass().getClassLoader());
super.service(req, resp);
currentThread.setContextClassLoader(oldContextClassLoader);
}
public void activate(ComponentContext context) {
System.out.println("Creating new greeter for " + context.getProperties().get("name")
+ ": " + context.getComponentInstance().toString());
}
public void activate() {
System.out.println("Activando la referencia al servicio");
}
public void deactivate(ComponentContext context) {
System.out.println("Deactivating greeter for " + context.getProperties().get("name")
+ ": " + context.getComponentInstance().toString());
}
public boolean greetServer(String input, String input2) throws Exception {
return zb.checkUser();
}
}
And the XML client is:
<?xml version="1.0" encoding="UTF-8" ?>
<scr:component name="serviceZB" xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0">
<implementation class="main.java.com.gwt.app.server.GreetingServiceImpl" />
<!-- <service>
<provide interface="main.java.com.gwt.app.client.GreetingService"/>
</service> -->
<reference name="zb" interface="service.IZBService"
bind="setZb" unbind="unsetZb" cardinality="1..1"
policy="static" />
</scr:component>
Why isn't the service injected if the service is deployed???
Here is a list of things you can try:
First, remove the "static" of zb, that could be the problem.
If you are using Equinox, add the -Dequinox.ds.print=true flag to the VM arguments and see more information about parsing XMLs and so
Of course, add sysouts to setZB and unsetZB :)
Remember that IZBService implementation needs a constructor without arguments
If you are using Equinox use the "list -c" command to obtain information of each component (it's cool because says exactly why a component is not registered).
Set the "inmediate=true" in XMLs to force to inmediatly activation.
You have both components with the same name, , which is kind of awkward when discussing them.
The reference on the client side has: cardinality="0..n" policy="dynamic". Which means it can be activated with zero to n references. Yet your code does not handle this. It seems to expect exactly one reference. Perhaps you should use cardinality="1..1" policy="static".
I am getting the following error in:
The CurrentThread needs to have it's ApartmentState set to ApartmentState.STA to be able to automate Internet Explorer.
With the following code:
[TestClass]
public class UnitTest1
{
[AssemblyInitialize]
public static void AssemblySetup(TestContext context)
{
}
[TestMethod]
[HostType("ASP.NET")]
[AspNetDevelopmentServerHost("C:\\SomePath", "/")]
[UrlToTest("http://localhost/HomeView.aspx")]
public void TestMethod1()
{
using(IE ie = new IE("http://localhost/HomeView.aspx",true))
{
ie.TextField(Find.ById("MainContent_txtDLNumber")).TypeText("a235801945550");
}
}
}
Is there a different approach for using WatIn with MsTest?
You will probably need to adjust your config accordingly, below should give you a clue
<configuration>
<configSections>
<sectionGroup name="NUnit">
<section name="TestRunner" type="System.Configuration.NameValueSectionHandler"/>
</sectionGroup>
</configSections>
<NUnit>
<TestRunner>
<!-- Valid values are STA,MTA. Others ignored. -->
<add key="ApartmentState" value="STA" />
</TestRunner>
</NUnit>
</configuration>
Consider updating your code to use NUnit 2.5 with RequiresSTA attribute.
Try this instead:
[STAThread]
static void Main(string[] args)
{
}