How do i enable cache in my RestAPI in c#? - c#

This is my EmployeeDetailsController.cs
namespace EmpApi.Controllers
{
[RoutePrefix("")]
public class EmployeeDetailsController : ApiController
{
[HttpGet]
[Route("Employees")]
public IEnumerable<Employee> Employees()
{
}
[HttpGet]
[Route("Details/{id}")]
public IEnumerable<Details> Details(int id)
{
}
[HttpGet]
[Route("TeamInfo/{id}")]
public IEnumerable<Team> TeamInfo(int id)
{
}
[HttpGet]
[Route("DetailsForTeam/{id}")]
public IEnumerable<Details> DetailsForTeam(int id)
{
;
}
[HttpPost]
[Route("PostEmp")]
public void PostEmp([FromBody] Employee cs)
{
}
[HttpPut]
[Route("PutEmp/{id}")]
public void PutEmp(int id, [FromBody]Employee cs)
{
}
[HttpDelete]
[Route("DeleteEmp/{id}")]
public void DeleteEmp(int id)
{
}
}
}
I made an API which has various services.
Suppose i call api/Employees,after i call api/Details/12 and then when i click GoBack button in browser, api/Employees should not be triggered.
How do i enable cache for my API.Please tell me the steps as I am new in WebApI.
Thanks in advance..

Add this code before your controller declaration as follows:
[OutputCache(VaryByParam = "*", Duration = 0, NoStore = true)]
public class EmployeeDetailsController : ApiController
{
...
}

Related

Two HttpGet on the same route in one controller [duplicate]

I want to build truly RESTful web service so don't want to leverage RPC-style, so have currently this:
[HttpGet]
[ActionName(nameof(GetByParticipant))]
public async Task<IActionResult> GetByParticipant([FromQuery]string participantId, [FromQuery]string participantType, [FromQuery]string programName)
{
}
[HttpGet]
[ActionName(nameof(GetByProgram))]
public async Task<IActionResult> GetByProgram([FromQuery]string programName)
{
}
And I believe that would work in ASP.NET Web API. But I'm getting an exception:
AmbiguousActionException: Multiple actions matched. The following actions matched route data and had all constraints satisfied:
TermsController.GetByParticipant (ParticipantTerms.Api)
TermsController.GetByProgram (ParticipantTerms.Api)
Neither of the attributes actually help:
[HttpGet]
[ActionName]
[FromQuery]
You can do this using an IActionConstraint.
Here is an example:
public class ExactQueryParamAttribute : Attribute, IActionConstraint
{
private readonly string[] keys;
public ExactQueryParamAttribute(params string[] keys)
{
this.keys = keys;
}
public int Order => 0;
public bool Accept(ActionConstraintContext context)
{
var query = context.RouteContext.HttpContext.Request.Query;
return query.Count == keys.Length && keys.All(key => query.ContainsKey(key));
}
}
[HttpGet]
[ActionName(nameof(GetByParticipant))]
[ExactQueryParam("participantId", "participantType", "programName")]
public async Task<IActionResult> GetByParticipant([FromQuery]string participantId, [FromQuery]string participantType, [FromQuery]string programName)
{
}
[HttpGet]
[ActionName(nameof(GetByProgram))]
[ExactQueryParam("programName")]
public async Task<IActionResult> GetByProgram([FromQuery]string programName)
{
}
When using from query you need to uniquely differentiate the actions' routes otherwise you will get the ambiguous action exception. Reason being api/action?participantId=1&participantType=2 is the same as api/action?programName=x
Suggestion:
public class ParticipantQuery {
public string participantId { get; set; }
public string participantType { get; set; }
public string programName { get; set; }
}
[Route("api/[controller]")]
public class TermsController : Controller {
[HttpGet("participants")] //GET api/terms/participants?participantId=123&....
[ActionName(nameof(GetByParticipant))]
public async Task<IActionResult> GetByParticipant([FromQuery]ParticipantQuery model) {
//...
}
[HttpGet("programs/{programName}")]//GET api/terms/programs/name
[ActionName(nameof(GetByProgram))]
public async Task<IActionResult> GetByProgram(string programName) {
//...
}
}
Or you can use one action that encapsulates the available parameters and branch the result based on the provided members
public class GetTermsQuery {
public string participantId { get; set; }
public string participantType { get; set; }
public string programName { get; set; }
}
[Route("api/[controller]")]
public class TermsController : Controller {
[HttpGet] //GET api/terms?participantId=123&....
public async Task<IActionResult> Get([FromQuery]GetTermsQuery model) {
//...
}
}
I've spent all day trying to do this and Andrew Radford's solution and this was perfect!
[HttpGet]
[ExactQueryParam("active")]
public IEnumerable<UserSelectAllSprocResult.DataRow> GetAll(
[FromQuery] bool active)
{
return ...
}
[HttpGet]
[ExactQueryParam("active", "companyId")]
public IEnumerable<UserSelectAllByCompanySprocResult.DataRow> GetByCompanyId(
[FromQuery] bool active, [FromQuery] int companyId)
{
return ...;
}

getting failed to parse JSON/YAML response using swagger when inheriting from custom base controller class

I am getting the error failed to parse JSON/YAML response. This occurs only if my controller inherits from a BaseController class. If I Remove the BaseController it works fine.
[Route("v1/helloworld")]
public class ValuesController : BaseController
{
private SystemManager _mgr { get; }
public ValuesController(SystemManager mgr):base(mgr)
{
_mgr = mgr;
}
// GET: api/values
[HttpGet]
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
// GET api/values/5
[HttpGet("{id}")]
public string Get(int id)
{
return "value";
}
// POST api/values
[HttpPost]
public void Post([FromBody]string value)
{
}
// PUT api/values/5
[HttpPut("{id}")]
public void Put(int id, [FromBody]string value)
{
}
// DELETE api/values/5
[HttpDelete("{id}")]
public void Delete(int id)
{
}
}
BaseController.cs
public abstract class BaseController : Controller
{
public SystemManager SysMgr { get; }
public LogWriter Logger
{
get { return SysMgr.Logger; }
}
public BaseController(SystemManager sysMgr)
{
SysMgr = sysMgr;
}
public async Task LogAsync(Exception ex)
{
await LogAsync(JsonConvert.SerializeObject(ex, Formatting.Indented));
}
public async Task LogAsync(string message)
{
var le = new LogEntry()
{
Message = message
};
await Logger.LogAsync(le);
}
public string GetUsername() => User.Claims.Where(a => a.Type == "Username").FirstOrDefault().Value;
public string GetIPAddress() => HttpContext.Features.Get<IHttpConnectionFeature>()?.RemoteIpAddress?.ToString() ?? string.Empty;
}
Was fixed by setting all method to protected in base controller class.

Is it possible to have multiple GETs that vary only by parameters in ASP.NET Core?

I want to build truly RESTful web service so don't want to leverage RPC-style, so have currently this:
[HttpGet]
[ActionName(nameof(GetByParticipant))]
public async Task<IActionResult> GetByParticipant([FromQuery]string participantId, [FromQuery]string participantType, [FromQuery]string programName)
{
}
[HttpGet]
[ActionName(nameof(GetByProgram))]
public async Task<IActionResult> GetByProgram([FromQuery]string programName)
{
}
And I believe that would work in ASP.NET Web API. But I'm getting an exception:
AmbiguousActionException: Multiple actions matched. The following actions matched route data and had all constraints satisfied:
TermsController.GetByParticipant (ParticipantTerms.Api)
TermsController.GetByProgram (ParticipantTerms.Api)
Neither of the attributes actually help:
[HttpGet]
[ActionName]
[FromQuery]
You can do this using an IActionConstraint.
Here is an example:
public class ExactQueryParamAttribute : Attribute, IActionConstraint
{
private readonly string[] keys;
public ExactQueryParamAttribute(params string[] keys)
{
this.keys = keys;
}
public int Order => 0;
public bool Accept(ActionConstraintContext context)
{
var query = context.RouteContext.HttpContext.Request.Query;
return query.Count == keys.Length && keys.All(key => query.ContainsKey(key));
}
}
[HttpGet]
[ActionName(nameof(GetByParticipant))]
[ExactQueryParam("participantId", "participantType", "programName")]
public async Task<IActionResult> GetByParticipant([FromQuery]string participantId, [FromQuery]string participantType, [FromQuery]string programName)
{
}
[HttpGet]
[ActionName(nameof(GetByProgram))]
[ExactQueryParam("programName")]
public async Task<IActionResult> GetByProgram([FromQuery]string programName)
{
}
When using from query you need to uniquely differentiate the actions' routes otherwise you will get the ambiguous action exception. Reason being api/action?participantId=1&participantType=2 is the same as api/action?programName=x
Suggestion:
public class ParticipantQuery {
public string participantId { get; set; }
public string participantType { get; set; }
public string programName { get; set; }
}
[Route("api/[controller]")]
public class TermsController : Controller {
[HttpGet("participants")] //GET api/terms/participants?participantId=123&....
[ActionName(nameof(GetByParticipant))]
public async Task<IActionResult> GetByParticipant([FromQuery]ParticipantQuery model) {
//...
}
[HttpGet("programs/{programName}")]//GET api/terms/programs/name
[ActionName(nameof(GetByProgram))]
public async Task<IActionResult> GetByProgram(string programName) {
//...
}
}
Or you can use one action that encapsulates the available parameters and branch the result based on the provided members
public class GetTermsQuery {
public string participantId { get; set; }
public string participantType { get; set; }
public string programName { get; set; }
}
[Route("api/[controller]")]
public class TermsController : Controller {
[HttpGet] //GET api/terms?participantId=123&....
public async Task<IActionResult> Get([FromQuery]GetTermsQuery model) {
//...
}
}
I've spent all day trying to do this and Andrew Radford's solution and this was perfect!
[HttpGet]
[ExactQueryParam("active")]
public IEnumerable<UserSelectAllSprocResult.DataRow> GetAll(
[FromQuery] bool active)
{
return ...
}
[HttpGet]
[ExactQueryParam("active", "companyId")]
public IEnumerable<UserSelectAllByCompanySprocResult.DataRow> GetByCompanyId(
[FromQuery] bool active, [FromQuery] int companyId)
{
return ...;
}

How to use dependency to mock data. MVC5

I am new to MVC5 and i am trying to work on 'search' functionality. my aim is get data from a dataservice.(that is, i enter data into a form and hit the search button, if theres a record it displays data).
I have created a dependency to mock the data(dummy data). How do i wire up my code to the contoller to achieve my purpose?. Please advice Thank you.
Heres my controller and my mock:
public class SearchController : Controller
{
private readonly ISearchResultsService _resultsService;
public SearchController() : this(DependencyFactory.NewResultsService())
{
}
public SearchController(ISearchResultsService resultsService)
{
_resultsService = resultsService;
}
// GET:Search
public ActionResult Index()
{
return View();
}
// GET: Search/Details/5
public ActionResult Details(int id)
{
return View();
}
// GET: Search/Create
public ActionResult Create()
{
return View();
}
// POST: Search/Create
[HttpPost]
public ActionResult Create(FormCollection collection)
{
try
{
// TODO: Add insert logic here
return();
}
catch
{
return View();
}
}
//[HttpPost]
//public ActionResult Index(SearchCriteria data)
//{
// var data = this._resultsService.FindClaims(data);
// return View(data);
//}
[HttpPost]
public ActionResult Index()
{
return View();
}
// GET: Search/Edit/5
public ActionResult Edit(int id)
{
return View();
}
// POST: Search/Edit/5
[HttpPost]
public ActionResult Edit(int id, FormCollection collection)
{
try
{
// TODO: Add update logic here
return RedirectToAction("Index");
}
catch
{
return View();
}
}
// GET: Search/Delete/5
public ActionResult Delete(int id)
{
return View();
}
// POST: Search/Delete/5
[HttpPost]
public ActionResult Delete(int id, FormCollection collection)
{
try
{
// TODO: Add delete logic here
return RedirectToAction("Index");
}
catch
{
return View();
}
}
}
public static class DependencyFactory
{
public static ISearchResultsService NewResultsService()
{
return new MockSearchResultsService();
}
}
public interface ISearchResultsService
{
List<Person> FindClaims(string firstName, string lastName);
}
public class MockSearchResultsService : ISearchResultsService
{
public List<Person> FindClaims(string firstName, string lastName)
{
return new List<Person>(new []{new Person{FirstName = "John", LastName = "Doe"}});//throw new NotImplementedException();
}
}
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
}
I recommend you to use some IoC container like http://autofac.org. You can configure your container and register your service like this way:
builder.RegisterType<MockSearchResultsService>().As<ISearchResultsService>()
All your dependencies will be automatically resolved:
public class SearchController : Controller
{
private readonly ISearchResultsService _resultsService;
public SearchController(ISearchResultsService resultsService)
{
_resultsService = resultsService;
}
}
Note that there is many IoC containers you can use. Try to search more about AutoFac, Ninject or Castle Windsor.

How can send dropdownlist value from Controller to another controller

I want to send dropdownlist selected value from Controller to another controller
and recuperate that value (i know how to send it ) but i dont know how to recuperat it
controller 1:
public class PosteController : Controller
{
[HttpPost]
public ActionResult Index(CandidateModel Id)
{
return RedirectToAction ("Inscription","Candidate",Id);
}
public class CandidateController : Controller
{
[HttpPost]
public ActionResult Inscription()
{
...........
}
Method 1:
Using Object Route :
public class PosteController : Controller
{
[HttpPost]
public ActionResult Index(CandidateModel Id)
{
return RedirectToAction ("Inscription","Candidate",new{ dropdownval=Id.val,Id });
}
public class CandidateController : Controller
{
public ActionResult Inscription(int? dropdownval)
{
...........
}
Method 2:
Using TempData:
public class PosteController : Controller
{
[HttpPost]
public ActionResult Index(CandidateModel Id)
{
TempData["Id"]=Id.val;
return RedirectToAction ("Inscription","Candidate");
}
public class CandidateController : Controller
{
public ActionResult Inscription()
{
var id=TempData["Id"];
...........
}
In above examples Id.val is the selected dropdown value.
You can use TempData for this.
[HttpPost]
public ActionResult Index(CandidateModel Id)
{
TempData["var"] = id;
return RedirectToAction ("Inscription","Candidate",Id);
}
public ActionResult Inscription()
{
var id = TempData["id"] as CandidateModel;
}

Categories