SwaggerRequestExample attribute does not work in ASP.NET MVC 5 (.NET Framework 4.5.2) - asp.net-mvc-5

I am toying with Swashbuckle.Examples package (3.10.0) in an ASP.NET MVC project. However, I cannot make request examples appear within the UI.
Configuration (SwaggerConfig.cs)
public static void Register()
{
var thisAssembly = typeof(SwaggerConfig).Assembly;
GlobalConfiguration.Configuration
.EnableSwagger(c => {
c.SingleApiVersion("v1", "TestApp.Web");
c.IncludeXmlComments(string.Format(#"{0}\bin\TestApp.Web.xml", System.AppDomain.CurrentDomain.BaseDirectory));
c.OperationFilter<ExamplesOperationFilter>();
c.OperationFilter<DescriptionOperationFilter>();
c.OperationFilter<AppendAuthorizeToSummaryOperationFilter>();
})
.EnableSwaggerUi(c => { });
}
Request example classes
public class EchoRequestExample : IExamplesProvider
{
public object GetExamples()
{
return new EchoInput { Value = 7 } ;
}
}
public class EchoInput
{
public int Value { get; set; }
}
Action
[HttpGet]
[Route("Echo")]
[CustomApiAuthorize]
[SwaggerRequestExample(typeof(EchoInput), typeof(EchoRequestExample))]
[ResponseType(typeof(EchoServiceModel))]
public HttpResponseMessage Echo([FromUri] EchoInput model)
{
var ret = new EchoServiceModel
{
Username = RequestContext.Principal.Identity.Name,
Value = value
};
return Request.CreateResponse(HttpStatusCode.OK, ret);
}
Swagger UI shows xml comments and output metadata (model and an example containing default values), but shows no request example. I attached to process and EchoRequestExample.GetExamples is not hit.
Question: How to make SwaggerRequestExample attribute work in ASP.NET MVC 5?
Note: Windows identity is used for authorization.

I received an answer from library owner here:
Swagger request examples can only set on [HttpPost] actions
It is not clear if this is a design choice or just a limitation, as I find [HttpGet] examples also relevant.

I know the feeling, lot's of overhead just for an example, I struggle with this for a while, so I created my own fork of swashbuckle, and after unsuccessful attempts to merge my ideas I ended up detaching and renaming my project and pushed to nuget, here it is: Swagger-Net
An example like that will be:
[SwaggerExample("id", "123456")]
public IHttpActionResult GetById(int id)
{
Here the full code for that: Swagger_Test/Controllers/IHttpActionResultController.cs#L26
Wondering how that looks like on the Swagger-UI, here it is:
http://swagger-net-test.azurewebsites.net/swagger/ui/index?filter=IHttpActionResult#/IHttpActionResult/IHttpActionResult_GetById

Related

c# MVC Site Map - very slow when using roles - very slow

I've installed MVC Site Map Provider for MVC5 and just used everything out of the the box. It works fine. Now I want to implement roles based menu trimming so assuming my controller:
public class Home: Controller
{
[Authorize(Roles="Admin")]
public ActionResult Index()
{
return View();
}
}
Now basically only Admin role users can see the menu. Perfect works fine.
Also to implement this I added to my web.config this line:
<add key="MvcSiteMapProvider_SecurityTrimmingEnabled" value="true" />
The problem is that it works but it's slow. It takes about 7 seconds for the page to load. If I remove the web.config line, basically removing menu trimming based on roles it takes ~300ms for the page to load. Something is wrong in here.
Any ideas why my menu trimming based on roles is slow? I haven't done any customizations.
The security trimming feature relies on creating a controller instance for every node in order to determine if the current user context has access.
The most likely cause of this slowness is that your controllers (or their base class) have too much heavy processing happening in the constructor.
public class HomeController
{
public HomeController() {
// Lots of heavy processing
System.Threading.Thread.Sleep(300);
};
}
The above example will add 300 ms to the page load time for every node that represents an action method in the HomeController. If your other controllers also have heavy processing during instantiation, they will also add additional time to each page load.
When following DI best practices, this is not an issue because heavy processing takes place in external services after the controller instance is created.
public interface IHeavyProcessingService
{
IProcessingResult DoSomethingExpensive();
}
public class HeavyProcessingService : IHeavyProcessingService
{
public HeavyProcessingService() {
}
public IProcessingResult DoSomethingExpensive() {
// Lots of heavy processing
System.Threading.Thread.Sleep(300);
}
}
public class HomeController
{
private readonly IHeavyProcessingService heavyProcessingService;
// The constructor does no heavy processing. It is deferred until after
// the instance is created by HeavyProcessingService.
// The only thing happening here is assignment of dependencies.
public HomeController(IHeavyProcessingService heavyProcessingService) {
if (heavyProcessingService == null)
throw new ArgumentNullException("heavyProcessingService");
this.heavyProcessingService = heavyProcessingService;
};
public ActionResult Index()
{
var result = this.heavyProcessingService.DoSomethingExpensive();
// Do something with the result of the heavy processing
return View();
}
public ActionResult About()
{
return View();
}
public ActionResult Contact()
{
return View();
}
}
Notice in the above example that no heavy processing happens in the constructor? This means that creating an instance of HomeController is very cheap. It also means that action methods that don't require the heavy processing to happen (as in About() and Contact() in the example) won't take the hit of heavy processing required by Index().
If not using DI, MVC still requires that a new controller instance be created for each request (controller instances are never shared between users or action methods). Although, in that case it is not as noticeable on a per user basis because only 1 instance is created per user. Basically, MvcSiteMapProvider is slowing down because of a pre-existing issue with your application (which you can now fix).
Even if you are not using DI, it is still a best practice to defer heavy processing until after the controller instance is created.
public class HomeController
{
private readonly IHeavyProcessingService heavyProcessingService;
public HomeController() {
this.heavyProcessingService = new HeavyProcessingService();
};
public ActionResult Index()
{
var result = this.heavyProcessingService.DoSomethingExpensive();
// Do something with the result of the heavy processing
return View();
}
}
But if moving heavy processing into external services in your application is not an option, you can still defer processing until its needed by moving the processing into another method so it is not too expensive to create controller instances.
public class HomeController
{
public HomeController() {
};
private IProcessingResult DoSomethingExpensive() {
// Lots of heavy processing
System.Threading.Thread.Sleep(300);
}
public ActionResult Index()
{
var result = this.DoSomethingExpensive();
// Do something with the result of the heavy processing
return View();
}
}
Although there is a bug posted for Route values not preserved correctly in v4?
But looks like it was fixed in version 4 next release.
Another Workaround to fix this problem is cache here is a related article.
MVC siteMap provider cache

Using Catel with Repository Pattern, EF6 and View Models

I cannot find any documentation on connecting a view model to a repository using Catel.
I have set up the Repository Pattern and my Models with EF6 Code First (all extending from ModelBase) but need to know how to use it with a ViewModel.
Do I need to create a service for the UnitOfWork? And if so, how? How will I use this in a ViewModel?
I am currently using the repository as a model in my viewmodel, but i do not think this is the correct way to do it? See my CompaniesViewModel below:
IUnitOfWork uow;
public CompaniesViewModel()
{
uow = new UnitOfWork<SoftwareSolutionsContext>();
CompanyRepository = uow.GetRepository<ICompanyRepository>();
}
public override string Title { get { return "Companies"; } }
protected override async Task Close()
{
uow.Dispose();
await base.Close();
}
protected override async Task Initialize()
{
Companies = new ObservableCollection<Company>(CompanyRepository.GetAll());
await base.Initialize();
}
public ObservableCollection<Company> Companies
{
get { return GetValue<ObservableCollection<Company>>(CompaniesProperty); }
set { SetValue(CompaniesProperty, value); }
}
public static readonly PropertyData CompaniesProperty = RegisterProperty("Companies", typeof(ObservableCollection<Company>), null);
[Model]
public ICompanyRepository CompanyRepository
{
get { return GetValue<ICompanyRepository>(CompanyRepositoryProperty); }
private set { SetValue(CompanyRepositoryProperty, value); }
}
public static readonly PropertyData CompanyRepositoryProperty = RegisterProperty("CompanyRepository", typeof(ICompanyRepository));
Essentially, I have 2 scenarios for working on the data:
getting all the data to display on a datagrid
selecting a record on the datagrid to open another view for editing a single record
Any guidance would be appreciated.
This is a very difficult subject, because there are basically a few options here:
Create abstractions in services (so the VM's only work with services, the services are your API into the db). The services work with the UoW
There are some people thinking that 1 is overcomplicated. In that case, you can simply use the UoW inside your VM's
Both have their pros and cons, just pick what you believe in most.

How to add Identity 2.0 users to an object

So I am trying to grasp EF6 and it's use of Identity 2.0 for making a many to many relationship. It is Visual Studio 2013 and the MVC 5 template.
I have a fresh MVC app with the following models:
public class Meeting
{
public Guid MeetingID { get; set; }
public string Title { get; set; }
public virtual ICollection<ApplicationUser> Attendees { get; set; }
}
public class ApplicationUser : IdentityUser
{
public ICollection<Meeting> Meetings { get; set; }
}
Then I scaffold a controller and views for Meetings. Now, for instance, if I just wanted to add every user as an attendee to my meeting, I would imagine that I could modify the Create action to look like the following:
public ActionResult Create(Meeting meeting)
{
if (ModelState.IsValid)
{
meeting.MeetingID = Guid.NewGuid();
db.Users.ForEachAsync(u => meeting.Attendees.Add(u));
db.Meetings.Add(meeting);
db.SaveChanges();
return RedirectToAction("Index");
}
else...
}
However I don't think it's working because I don't see it in my LocalDB and if I add this to the detail view for a meeting I get no results:
#{foreach (var item in Model.Attendees)
{
<li>#item.UserName</li>
}}
As a final note, I have two users in the LocalDB, test and test2.
What tutorial or documentation will allow me to make this work?
* Edit *
So I have tried your suggestion (I'll admit, I am unfamiliar with async and await and how to implement it), and I had to modify the controller to allow me to use await so I'm not sure if I'm doing this correctly now, but I got the following to compile and I get run time error of 'object reference not set to an instance of an object' :
public async Task<ActionResult> Create(Meeting meeting)
{
if (ModelState.IsValid)
{
meeting.MeetingID = Guid.NewGuid();
await db.Users.ForEachAsync(u => meeting.Attendees.Add(u));
db.Meetings.Add(meeting);
db.SaveChanges();
(is it possible I'm missing some setup of my model on Entity Framework? The project is exactly the code shown above plus defaults.)
You're going to kick yourself :)
(Drumroll)
You forgot to add await before your ForEachAsync line:
await db.Users.ForEachAsync(u => meeting.Attendees.Add(u));
Without await the application happily continues on and saves the record, all before that async process has completed.
UPDATE
Most likely you haven't initialized the Attendees collection. Just set it to a new List<ApplicationUser> in your constructor.

MVC5/API2 CreateErrorResponse in custom ActionFilterAttribute OnActionExecuting

With MVC4 I was able to create and register a global action filter that would check the model state prior to the action's execution and return the serialized ModelState before any damage could be done.
public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext)
{
if (!actionContext.ModelState.IsValid)
{
actionContext.Request.CreateErrorResponse(HttpStatusCode.BadRequest, actionContext.ModelState);
}
}
However, with MVC5, I am having trouble finding Request and therefore CreateErrorResponse
public override void OnActionExecuting(ActionExecutingContext nActionExecutingContext)
{
if (!nActionExecutingContext.Controller.ViewData.ModelState.IsValid)
{
nActionExecutingContext.Result = // Where is Request.CreateErrorResponse ?
}
}
I realize that I could create a custom response class to assign to Result but I'd rather use what's built-in if CreateErrorResponse is still available.
Any idea where I can find it relative to an ActionExecutingContext in MVC5 / Web API 2?
I know this is an old question but I recently had the same problem and solved it using
public override void OnActionExecuting(ActionExecutingContext context)
{
if (!context.ModelState.IsValid)
{
context.Result = new BadRequestObjectResult(context.ModelState);
}
}

Spec fails when run by mspec.exe, but passes when run by TD.NET

I wrote about this topic in another question.
However, I've since refactored my code to get rid of configuration access, thus allowing the specs to pass. Or so I thought. They run fine from within Visual Studio using TestDriven.Net. However, when I run them during rake using the mspec.exe tool, they still fail with a serialization exception. So I've created a completely self-contained example that does basically nothing except setup fake security credentials on the thread. This test passes just fine in TD.Net, but blows up in mspec.exe. Does anybody have any suggestions?
Update: I've discovered a work-around. After researching the issue, it seems the cause is that the assembly containing my principal object is not in the same folder as the mspec.exe. When mspec creates a new AppDomain to run my specs, that new AppDomain has to load the assembly with the principal object in order to deserialize it. That assembly is not in the same folder as the mspec EXE, so it fails. If I copied my assembly into the same folder as mspec, it works fine.
What I still don't understand is why ReSharper and TD.Net can run the test just fine? Do they not use mspec.exe to actually run the tests?
using System;
using System.Security.Principal;
using System.Threading;
using Machine.Specifications;
namespace MSpecTest
{
[Subject(typeof(MyViewModel))]
public class When_security_credentials_are_faked
{
static MyViewModel SUT;
Establish context = SetupFakeSecurityCredentials;
Because of = () =>
SUT = new MyViewModel();
It should_be_initialized = () =>
SUT.Initialized.ShouldBeTrue();
static void SetupFakeSecurityCredentials()
{
Thread.CurrentPrincipal = CreatePrincipal(CreateIdentity());
}
static MyIdentity CreateIdentity()
{
return new MyIdentity(Environment.UserName, "None", true);
}
static MyPrincipal CreatePrincipal(MyIdentity identity)
{
return new MyPrincipal(identity);
}
}
public class MyViewModel
{
public MyViewModel()
{
Initialized = true;
}
public bool Initialized { get; set; }
}
[Serializable]
public class MyPrincipal : IPrincipal
{
private readonly MyIdentity _identity;
public MyPrincipal(MyIdentity identity)
{
_identity = identity;
}
public bool IsInRole(string role)
{
return true;
}
public IIdentity Identity
{
get { return _identity; }
}
}
[Serializable]
public class MyIdentity : IIdentity
{
private readonly string _name;
private readonly string _authenticationType;
private readonly bool _isAuthenticated;
public MyIdentity(string name, string authenticationType, bool isAuthenticated)
{
_name = name;
_isAuthenticated = isAuthenticated;
_authenticationType = authenticationType;
}
public string Name
{
get { return _name; }
}
public string AuthenticationType
{
get { return _authenticationType; }
}
public bool IsAuthenticated
{
get { return _isAuthenticated; }
}
}
}
Dan,
thank you for providing a reproduction.
First off, the console runner works differently than the TestDriven.NET and ReSharper runners. Basically, the console runner has to perform a lot more setup work in that it creates a new AppDomain (plus configuration) for every assembly that is run. This is required to load the .dll.config file for your spec assembly.
Per spec assembly, two AppDomains are created:
The first AppDomain (Console) is created
implicitly when mspec.exe is
executed,
a second AppDomain is created by mspec.exe for the assembly containing the specs (Spec).
Both AppDomains communicate with each other through .NET Remoting: For example, when a spec is executed in the Spec AppDomain, it notifies the Console AppDomain of that fact. When Console receives the notification it acts accordingly by writing the spec information to the console.
This communiciation between Spec and Console is realized transparently through .NET Remoting. One property of .NET Remoting is that some properties of the calling AppDomain (Spec) are automatically included when sending notifications to the target AppDomain (Console). Thread.CurrentPrincipal is such a property. You can read more about that here: http://sontek.vox.com/library/post/re-iprincipal-iidentity-ihttpmodule-serializable.html
The context you provide will run in the Spec AppDomain. You set Thread.CurrentPrincipal in the Because. After Because ran, a notification will be issued to the Console AppDomain. The notification will include your custom MyPrincipal that the receiving Console AppDomain tries to deserialize. It cannot do that since it doesn't know about your spec assembly (as it is not included in its private bin path).
This is why you had to put your spec assembly in the same folder as mspec.exe.
There are two possible workarounds:
Derive MyPrincipal and MyIdentity from MarshalByRefObject so that they can take part in cross-AppDomain communication through a proxy (instead of being serialized)
Set Thread.CurrentPrincipal transiently in the Because
(Text is required for formatting to work -- please ignore)
Because of = () =>
{
var previousPrincipal = Thread.CurrentPrincipal;
try
{
Thread.CurrentPrincipal = new MyPrincipal(...);
SUT = new MyViewModel();
}
finally
{
Thread.CurrentPrincipal = previousPrincipal;
}
}
ReSharper, for example, handles all the communication work for us. MSpec's ReSharper Runner can hook into the existing infrastructure (that, AFAIK, does not use .NET Remoting).

Resources