ASP.Net Web API Help Page Area returning empty output - asp.net-web-api

I have a preexisting MVC app that I added Web API and Web API Self Documentation using Nuget. While the Web API controllers function fine (return valid responses to HTTP requests) the Help controller is not finding any Web API methods to document.
In the Help controller Index action "Configuration.Services.GetApiExplorer().ApiDescriptions" is returning with 0 results.
What populated ApiDescriptions and are there any config settings I need to set to expose my api to documentations?
The Help Area is a separate area from the rest of my application. Is this causing the piece that finds the Controllers to not find my controllers? Furthermore, I even added a help snipped to the HelpController itself, which still resulted in no API descriptions.
I do also have special routing for my API controllers, so I'm not sure if that's relevant.

After some more searching i found this post which also refers to this post
As mentioned in the first post, Glimpse is the culplit, this workaround solved the issue for me:
<glimpse defaultRuntimePolicy="On" endpointBaseUri="~/Glimpse.axd">
<inspectors>
<ignoredTypes>
<add type="Glimpse.AspNet.Inspector.RoutesInspector, Glimpse.AspNet"/>
</ignoredTypes>
</inspectors>
</glimpse>
This is also a known issue and the workaround is described on this Glimpse GitHub Issue.

I have the same problem and i don't use Glimpse and i solve the problem like this:
In the ProjectName\Areas\HelpPage\Controllers\HelpController.cs file comment the constructors because is not called the implicit constructor public HelpController() : this(GlobalConfiguration.Configuration) default is called the constructor with the parameter public HelpController(HttpConfiguration config) and this initialization of the Configuration property is incorect. And you cand solve this problem like this:
Solution 1:
Comment/Remove the constructors.
public class HelpController : Controller
{
private const string ErrorViewName = "Error";
// public HelpController()
// : this(GlobalConfiguration.Configuration)
// {
// }
// public HelpController(HttpConfiguration config)
// {
// Configuration = config;
// }
/// <summary>
/// GlobalConfiguration By default
/// </summary>
protected static HttpConfiguration Configuration
{
get { return GlobalConfiguration.Configuration; }
}
public ActionResult Index()
{
ViewBag.DocumentationProvider = Configuration.Services.GetDocumentationProvider();
return View(Configuration.Services.GetApiExplorer().ApiDescriptions);
}
....
Solution 2:
inject the default constructor by add this attribute [InjectionConstructor].
public class HelpController : Controller
{
private const string ErrorViewName = "Error";
[InjectionConstructor]
public HelpController()
: this(GlobalConfiguration.Configuration)
{
}
public HelpController(HttpConfiguration config)
{
Configuration = config;
}
/// <summary>
/// GlobalConfiguration By default
/// </summary>
protected static HttpConfiguration Configuration { get; private set; }
....
And problem solved.

I was able to solve this by adding GlobalConfiguration.Configure (WebApiConfig.Register); in my Application_Start () method. Because my application uses OWIN I was registering my APIs only in Startup.Configuration (IAppBuilder app).

After installing HelpPages package from NuGet package manager- Navigate to WebApplication1\Areas\HelpPage\App_Start\HelpPageConfig.cs and uncomment the line below
config.SetDocumentationProvider(new XmlDocumentationProvider(
HttpContext.Current.Server.MapPath("~/App_Data/XmlDocument.xml")));
Also add App_Data/XmlDocument.xml to WebApplication > Properties > Build > Check XML Documentation File

Related

How to create session of object value in asp.net core version 2.2.0?

In Microsoft.AspNetCore.Session version 2.2.0 how to create session of object value.
I have tried to read various article, but when I am trying to apply same it gives me error, because there is no overload as 'SetString'.
public static class SessionHelper
{
public static void SetObjectAsJson<T>(this ISession session, string key, object value)
{
session.SetString(key, JsonConvert.SerializeObject(value));
}
public static T GetObjectFromJson<T>(this ISession session, string key)
{
var value = session.GetString(key);
return value == null ? default(T) : JsonConvert.DeserializeObject<T>(value);
}
}
In Asp.Net Core apart from setting and getting session string, you also have add the SessionMiddleware to the pipeline, do this app.UseSession() before the app.UseMvc() in the Configure method in your startup.cs file. After that in your ConfigureServices method, add the following service.
services.AddSession(options =>
{
//Replace {mins} with the time you want, usually around 20-30.
options.IdleTimeout = TimeSpan.FromMinutes({mins});
});
and then you can continue with the SessionHelper class.
Also the name of your class is wrong, it should be called SessionExtensions and not SessionHelper, maybe that's why your extension doesn't get registered with HttpContext.Session.
Hope this helps.

ShouldSerialize* methods are not called in Web API documentation using SWAGGER

I am using Swagger for Web API documentation.
In my Web API, I have entities as below:
public class BaseEntity
{
public string BaseEntProp1{get;set;}
public string BaseEntProp2{get;set;}
public virtual bool ShouldSerializeBaseEntProp1()
{
return true;
}
public virtual bool ShouldSerializeBaseEntProp1()
{
return true;
}
}
public class DerivedEntity1 : BaseEntity
{
[JsonIgnore]
public string DerEntProp1{get;set;}
public string DerEntProp2{get;set;}
public override bool ShouldSerializeBaseEntProp1()
{
return false;
}
public override bool ShouldSerializeBaseEntProp1()
{
return false;
}
}
I used DerivedEntity1 as the input parameter for a Web API method and generated the swagger documentation.
Until this it is fine but the problem is, DerivedEntity1 JSON string in that documentation shows both BaseEntProp1 & BaseEntProp2 which are supposed to be excluded. Can someone help me how to exclude those?
Note:
1. DerivedEntity1's DerEntProp1 property is properly excluded.
2. Just to confirm, in my Startup method after the documentation is generated, I have hardcoded following:
var temp = new DerivedEntity1 {
BaseEntProp1 = "should be ignored",
BaseEntProp2 = "this also should be ignored"};
string tempJson = JsonConvert.SerializeObject(temp);
Above test passed, i.e., tempJson doesn't have both BaseEntProp1 & BaseEntProp2. So, I suspect somehow SWAGGER is failing to call proper ShouldSerialize* methods. Any help is highly appreciated.
Thanks
Finally I solved it in a different way as the problem is not related to Swagger.
I have created base abstract classes with virtual properties. In derived classes I have overloaded those properties and decorated with JsonIgnore attribute. This solved my problem.

ASP.Net MVC 3 IF Statement outside Controller Action

I am developing an ASP.Net MVC 3 Web Application. I need to have my website secured with an SSL certificate, however, I only want this used when the application is on my live server, NOT on my test server.
Therefore, I setup an AppSetting in my Web Config like so
<appSettings>
<add key="SSL" value="false" />
</appSettings>
Then in my Account Controller I get this value (either True or False) and using the value, decide whether or not to set the RequiresHttps attribute on my LogOn Action. I would like to do something like so
public class AccountController : Controller
{
public string SSL = System.Configuration.ConfigurationManager.AppSettings["SSL"];
if (SSL.Equals("true"))
{
[RequireHttps]
}
public ActionResult LogOn()
{
return View();
}
}
But I know I can't put my IF statement where it currently is, however, hopefully you get the idea of what I am trying to achieve.
Does anyone have any suggestions as to how I can implement my idea?
Thanks.
Subclass the RequireHttpAttribute (note this code is changed from my original answer - this new version will be more efficient):
public class RequireHttpsIfEnabledAttribute : RequireHttpsAttribute
{
//this setting can't be changed without a recycle, so get it once and cache it.
private static readonly Lazy<bool> HttpsRequired = new Lazy<bool>(() => {
//if the AppSettings["SSL"] returns null you raise an exception if you do a
//.Equals on it - so do it on the constant instead. And make sure it's case
//insensitive!
return "true".Equals(System.Configuration.ConfigurationManager.AppSettings["SSL"],
StringComparison.OrdinalIgnoreCase);
});
public override void OnAuthorization(AuthorizationContext filterContext)
{
//calling the base will fire the HTTPS check. Not calling it will allow
//non-SSL requests through
if (HttpsRequired.Value)
base.OnAuthorization(filterContext);
}
}
Now you just decorate your controllers/actions as before - but with your new attribute:
[RequireHttpsIfEnabled]
public class AccountController : Controller
{
//....
}

MVC 3 sub Site?

I have a very basic site that works fine on its own but when I create a duplicate of the site and attempt to add it to a sub domain (then convert it to a application) I get a error when I attempt to any controller which has the below settings at the top:
public class AccountController : Controller
{
// This constructor is used by the MVC framework to instantiate the controller using
// the default forms authentication and membership providers.
private CustomMembershipDB datacontext;
public AccountController()
: this(null, null)
{
datacontext = new CustomMembershipDB();
}
// This constructor is not used by the MVC framework but is instead provided for ease
// of unit testing this type. See the comments at the end of this file for more
// information.
public AccountController(IFormsAuthentication formsAuth, IMembershipService service)
{
FormsAuth = formsAuth ?? new FormsAuthenticationService();
MembershipService = service ?? new AccountMembershipService();
}
public IFormsAuthentication FormsAuth
{
get;
private set;
}
public IMembershipService MembershipService
{
get;
private set;
}
Error I get:
Description: An error occurred during the processing of a configuration file required to service this request. Please review the specific error details below and modify your configuration file appropriately.
Parser Error Message: The entry 'EFMembershipProvider' has already been added.
IIS seems to be complaining about a duplicate Membership provider being set on the same domain and not sure simply renaming it will solve this one? Any Idea appreciated as I'm a newbie and this is above me!
I suppose that your "subsite" is a virtual directory of the first one. Root's Web.config settings are inherited to virtual directories.
That means that by default your subsite gets all providers declared in your top site.
To prevent this behavior you can use this directive inheritInChildApplications=false on your main Web.config or simply avoid to (re)declare the EFMembershipProvider in your subsite.

ASP.NET MVC How to access a property in the Global.asax file from the Controller?

in the Global.asax file, I manage some threads, and - from the Controller - I need to invoke an event of the one's thread. Is it possible to have access to that thread ?
You could use the application state to store some object that will be shared among all users of the application:
protected void Application_Start()
{
Application["foo"] = "bar";
...
}
and inside your controller you can access this property:
public ActionResult Index()
{
var foo = HttpContext.Application["foo"] as string;
...
}
You could if it were any other kind of object, like a string, because you'll need to declare the property as static in the Global.asax to make it available to the rest of the app:
public class Application : HttpApplication
{
// This is the class declared in Global.asax
// Your route definitions and initializations are also in here
public static string MyProperty { get; set; }
}
This will be available to the rest of the application. You can call by doing:
public ActionResult MyAction()
{
var bla = Application.MyProperty;
}
That said, I dont think you want to make a Thread available to the rest of the app this way.

Resources