I've been trying to get Web Api to work with Sitecore 8.1.
I installed this package: https://www.nuget.org/packages/Krusen.Sitecore.WebApi.Custom/ and I modified the ConfigureWebApi to the following:
public class ConfigureWebApi
{
public void Process(PipelineArgs args)
{
GlobalConfiguration.Configure(config => config.Routes.MapHttpRoute("API Default", "api/{controller}/{id}",
new { id = RouteParameter.Optional }));
GlobalConfiguration.Configure(config => config.MapHttpAttributeRoutes());
GlobalConfiguration.Configure(ReplaceControllerSelector);
}
private static void ReplaceControllerSelector(HttpConfiguration config)
{
config.Services.Replace(typeof (IHttpControllerSelector),
new CustomHttpControllerSelector(config, new NamespaceQualifiedUniqueNameGenerator()));
}
}
However, whenever I use post requests, I get the following error:
{"Message":"The requested resource does not support http method
'POST'."}. Get requests work.
This is the implementation of the controller:
[RoutePrefix("api/authentication")]
public class AuthenticationController : ApiController
{
[Route("email")]
[HttpPost]
public bool Login([FromBody] string email)
{
return true;
}
}
I figured out what the error was. When my controller was called AuthenticationController it gave the following error:
The requested document was not found
If I called it something else, the web api worked as a charm e.g.
public TestController : ApiController {
//Code goes here
}
Related
As in Net MVC, I want to save the response cache to the server (it's called outputcache), but there is no such feature in Net Core or Net 5. I couldn't find an alternative method. Thank you in advance.
You can use WebEssentials.AspNetCore.OutputCaching nuget to achieve your requirement.
Follow the steps below:
1.Add the middleware:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddOutputCaching();
//other middleware...
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseOutputCaching();
//other middleware...
}
}
2.Add OutputCache attribute to the action:
[OutputCache(Duration = 600)]
public IActionResult Index()
{ ... }
A sample code for testing:
Controller:
[OutputCache(Duration = 600)]
public IActionResult Index()
{
return View(DateTime.Now);
}
View:
#model DateTime
Time of request: #Model.ToString()
Try requesting the page and notice that the date and time remains the same, even when reloading the page, until the cache has expired.
OutputCache contains not least Duration option, but also other options, such as VaryByHeader, VaryByParam and so on...
More details you can refer to the github repo for WebEssentials.AspNetCore.OutputCaching
I have an ASP.NET Core blank project, and it works great to serve static files through https://localhost/filename. Now I want to add MVC functions to it. But referencing https://learn.microsoft.com/en-us/aspnet/core/tutorials/first-mvc-app/adding-controller?view=aspnetcore-2.2&tabs=visual-studio , after adding "Controllers" folder, add a controller class:
public class HelloWorldController : Controller
{
//
// GET: /HelloWorld/Welcome/
public string Welcome()
{
return "This is the Welcome action method...";
}
}
StartUp.cs is like:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseMvc();
app.UseStaticFiles();
}
Builder is like:
return WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>();
after all this, I still can't access "https://localhost/HelloWorld/Welcome/".
What did I omit?
You have no default route specified, or routing of any sort for that matter. The quickest fix is to change app.UseMvc() to app.UseMvcWithDefaultRoute(). Alternatively, you can add attribute routes:
[Route("[controller]")]
public class HelloWorldController : Controller
{
[HttpGet("Welcome")]
public string Welcome()
{
return "This is the Welcome action method...";
}
}
I have a well known issue where my Web API complains that my controller does not have a parameterless constructor. I have been through many pages and questions on this but cant seem to find the issue.
I installed Unity using Nuget command Install-Package Unity.WebAPI. The UnityConfig was created properly.
This is my UnityConfig file:
public static class UnityConfig
{
public static void RegisterComponents()
{
var container = new UnityContainer();
container.RegisterType<IImportHeadService, ImportHeadService>();
container.RegisterType<IImportDetailService, ImportDetailService>();
container.RegisterType<ICurrencyService, CurrencyService>();
container.RegisterType<ISupplierService, SupplierService>();
container.RegisterType<IKPIService, KPIService>();
GlobalConfiguration.Configuration.DependencyResolver = new UnityDependencyResolver(container);
}
}
I then registered the UnityConfig in my Global.asax file as below:
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
UnityConfig.RegisterComponents();
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
}
And finally, here is my ImportController which is what I am trying to call through fiddler:
public class ImportController : ApiController
{
private IImportHeadService _importHeadService;
private IImportDetailService _importDetailService;
public ImportController(IImportHeadService importHeadService, IImportDetailService importDetailService)
{
_importHeadService = importHeadService;
_importDetailService = importDetailService;
}
[HttpGet, Route("api/Import/Info")]
public HttpResponseMessage GetInfo()
{
return Request.CreateResponse(HttpStatusCode.OK, "Import Tracker v1.0 - Import Controller");
}
}
As you can see it is a very simple controller at this point but I receive the following error:
An error occurred when trying to create a controller of type 'ImportController'. Make sure that the controller has a parameterless public constructor.
OK, so I was being a bit silly after all. My services have a parameter in their constructor for a context. Once I added the context into the Unity configuration. It all worked.
I am putting together a talk for a local Code Camp and am trying to understand the nuances of HTTP Verbs in ApiController. Several things about ApiController significantly changed between Beta, RC and final release, and the advice on how you can set this up is conflicting and sometimes wrong.
Assuming I am just leaving the standard routing in WebApiConfig:
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
(since you can really put things on their head if you add in an {action} parameter here)
I understand how the convention is working for simple Crud calls like:
// GET api/values
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
// GET api/values/5
public string Get(int id)
{
return "value";
}
// POST api/values
public void Post([FromBody]string value)
{
}
Or that you can change these as long as they start with the verb name:
// GET api/values/5
public string GetMyStuff(int id)
{
return "value";
}
However, the initial spec says that ApiController supports Get, Put, Post and Delete.
Yet I can add methods for:
public void HeadOfTheClass()
{
}
Which works for a Head verb, but I can’t add methods for the obscure or non-existent verbs:
public void MKCOL()
{
}
public void Bubba()
{
}
What is the full list of Native “Supported” verbs?
I can however add support for these methods by using the AcceptVerb attribute:
[AcceptVerbs("MKCOL")]
public void MKCOL()
{
}
[AcceptVerbs("Bubba")]
public void Bubba()
{
}
This also works, or for any “defined” verb use the Http attributes:
[HttpHead]
public void HeadOfTheClass()
{
}
[HttpGet]
public void Bubba()
{
}
Which is correct or preferred? (There was also attributes like [GET] and [POST] as well, are these deprecated?)
Are [HttpBindNever] and [NonAction] equivalent?
I love open source. :)
From ReflectedHttpActionDescriptor:
private static readonly HttpMethod[] _supportedHttpMethodsByConvention =
{
HttpMethod.Get,
HttpMethod.Post,
HttpMethod.Put,
HttpMethod.Delete,
HttpMethod.Head,
HttpMethod.Options,
new HttpMethod("PATCH")
};
When I use a web type registered with autofac from an automapper mapping, I get this error:
No scope with a Tag matching 'httpRequest' is visible from the scope in which the instance was requested. This generally indicates that a component registered as per-HTTP request is being reqested by a SingleInstance() component (or a similar scenario.) Under the web integration always request dependencies from the DependencyResolver.Current or ILifetimeScopeProvider.RequestLifetime, never from the container itself.
When another type is resolved in the mapping it works.
When a web type is resolved from the controller it works.
Why doesnt web (or any other httprequest scoped?) types get successfully resolved in my mapping?
protected void Application_Start()
{
var builder = new ContainerBuilder();
builder.RegisterModule<AutofacWebTypesModule>();
builder.RegisterControllers(Assembly.GetExecutingAssembly());
builder.RegisterModelBinders(Assembly.GetExecutingAssembly());
builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly())
.AssignableTo<Profile>()
.As<Profile>()
;
builder.Register(c => Mapper.Engine)
.As<IMappingEngine>();
builder.RegisterType<AnotherType>()
.As<IAnotherType>();
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
var profiles = container.Resolve<IEnumerable<Profile>>();
Mapper.Initialize(c => profiles.ToList().ForEach(c.AddProfile));
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}
public class HomeController : Controller
{
private readonly IMappingEngine _mapper;
private readonly Func<HttpContextBase> _httpContext;
public HomeController(IMappingEngine mapper, Func<HttpContextBase> httpContext)
{
_mapper = mapper;
_httpContext = httpContext;
}
public ActionResult Index()
{
var test = _httpContext.Invoke();
return View(_mapper.Map<Model, ViewModel>(new Model()));
}
}
public class MyProfile : Profile
{
private readonly Func<HttpContextBase> _httpContext;
private readonly Func<IAnotherType> _anotherType;
public MyProfile(Func<HttpContextBase> httpContext, Func<IAnotherType> anotherType)
{
_httpContext = httpContext;
_anotherType = anotherType;
}
protected override void Configure()
{
CreateMap<Model, ViewModel>()
.ForMember(d => d.Url, o => o.ResolveUsing(s =>
{
var test = _anotherType.Invoke().GetAValue();
return _httpContext.Invoke().Request.Url;
}))
;
}
}
public interface IAnotherType
{
string GetAValue();
}
public class AnotherType : IAnotherType
{
public string GetAValue() { return "a value"; }
}
public class ViewModel
{
public string Url { get; set; }
}
public class Model
{
}
EDIT: Its easy to create an empty MVC project, paste the code and try it out and see for yourself.
EDIT: Removed the ConstructServicesUsing call because its not required by the example. No services are resolved through AutoMapper in the example.
#rene_r above is on the right track; adapting his answer:
c.ConstructServicesUsing(t => DependencyResolver.Current.GetService(t))
Still might not compile but should get you close.
The requirement is that the call to DependencyResolver.Current is deferred until the service is requested (not kept as the value returned by Current when the mapper was initialised.)
I think you should use DependencyResolver.Current.Resolve instead of container.Resolve in
Mapper.Initialize(c =>
{
c.ConstructServicesUsing(DependencyResolver.Current);
profiles.ToList().ForEach(c.AddProfile);
});
I recently had a similar problem and it turned out to be a bad setup in my bootstrapper function. The following autofac setup did it for me.
builder.Register(c => new ConfigurationStore(new TypeMapFactory(), AutoMapper.Mappers.MapperRegistry.Mappers))
.AsImplementedInterfaces()
.SingleInstance();
builder.Register(c => Mapper.Engine)
.As<IMappingEngine>()
.SingleInstance();
builder.RegisterType<TypeMapFactory>()
.As<ITypeMapFactory>()
.SingleInstance();
I did not have to specify resolver in the Mapper.Initialize() function. Just called
Mapper.Initialize(x =>
{
x.AddProfile<DomainToDTOMappingProfile>();
});
after the bootstrapped and it works fine for me.