implementing search not working in web api - asp.net-mvc

Working on a web api for our mobile app, and we can't seem to get our search method to work.
When we try to call from the api we get the following result for our search method
<Error>
<Message>
No HTTP resource was found that matches the request URI 'https://hippokros- api.azurewebsites.net/api/Recommends/GetCardRecommendsByFriendId/100000097477513'.
</Message>
<MessageDetail>
No action was found on the controller 'Recommends' that matches the request.
</MessageDetail>
</Error>
We get a 502 HTTP request in Fiddler, but when we call GetRecommends/1 and pass in the id we get results.
Are controller code is short so i'll just display all of it
public class RecommendsController : ApiController
{
private mtgServiceEntities db = new mtgServiceEntities();
// GET: api/Recommends
[HttpGet]
public IQueryable<Recommend> GetRecommends()
{
return db.Recommends;
}
// GET: api/Recommends/5
[ResponseType(typeof(Recommend))]
[HttpGet]
public IHttpActionResult GetRecommend(int id)
{
Recommend recommend = db.Recommends.Find(id);
if (recommend == null)
{
return NotFound();
}
return Ok(recommend);
}
// GET: api/Recommends/5
[ResponseType(typeof(Recommend))]
[HttpGet]
public IHttpActionResult GetRecommend(string cardname)
{
List<Recommend> recommend = db.Recommends.Where(x => x.card_name == cardname).ToList();
if (recommend == null)
{
return NotFound();
}
return Ok(recommend);
}
//GET: api/Recommend/Search/cardname
[ResponseType(typeof(Recommend))]
[HttpGet]
public IHttpActionResult GetFriendRecommendsByCardName(string cardname)
{
List<Recommend> recommends = db.Recommends.Where(x => x.card_name == cardname).ToList();
return Ok(recommends);
}
[ResponseType(typeof(Recommend))]
[HttpGet]
public IHttpActionResult GetCardRecommendsByFriendId(string friendId)
{
List<Recommend> recommends = db.Recommends.Where(x => x.facebookId == friendId).ToList();
return Ok(recommends);
}
// PUT: api/Recommends/5
[ResponseType(typeof(void))]
public IHttpActionResult PutRecommend(int id, Recommend recommend)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
if (id != recommend.ID)
{
return BadRequest();
}
db.Entry(recommend).State = EntityState.Modified;
try
{
db.SaveChanges();
}
catch (DbUpdateConcurrencyException)
{
if (!RecommendExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return StatusCode(HttpStatusCode.NoContent);
}
// POST: api/Recommends
[ResponseType(typeof(Recommend))]
public IHttpActionResult PostRecommend(Recommend recommend)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
db.Recommends.Add(recommend);
try
{
db.SaveChanges();
}
catch (DbUpdateException)
{
if (RecommendExists(recommend.ID))
{
return Conflict();
}
else
{
throw;
}
}
return CreatedAtRoute("DefaultApi", new { id = recommend.ID }, recommend);
}
// DELETE: api/Recommends/5
[ResponseType(typeof(Recommend))]
public IHttpActionResult DeleteRecommend(int id)
{
Recommend recommend = db.Recommends.Find(id);
if (recommend == null)
{
return NotFound();
}
db.Recommends.Remove(recommend);
db.SaveChanges();
return Ok(recommend);
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
db.Dispose();
}
base.Dispose(disposing);
}
private bool RecommendExists(int id)
{
return db.Recommends.Count(e => e.ID == id) > 0;
}
}
and our routing in the webapiconfig file is as follows
public static void Register(HttpConfiguration config)
{
//Web API configuration and services
config.EnableCors();
// Web API configuration and services
// Configure Web API to use only bearer token authentication.
config.SuppressDefaultHostAuthentication();
config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
We're not sure what setting or configuration we have wrong, but basically it's telling us there's nothing there when we know we have the right URL and we're using https to call it.
Please help!

I use attribute routing because I can easily see what is mapped to what:) I recommend to read this article to better understand the Web API Attribute routing.
To match your address you can try the following code:
[RoutePrefix("api/recommends")]
public class RecommendsController : ApiController
{
...
Route("GetCardRecommendsByFriendId/{friendId}")]
[ResponseType(typeof(Recommend))]
[HttpGet]
public IHttpActionResult GetCardRecommendsByFriendId(string friendId)
{
List<Recommend> recommends = db.Recommends.Where(x => x.facebookId == friendId).ToList();
return Ok(recommends);
}
}

Related

Why does authorization fails when I publish on IIS in aspnet core?

I have used aspnet core identity for login functionality in my webapp. I have published my webapp on IIS. It loads perfectly but when I enter username and password and navigate to action methods bearing authorize attribute the applications fails. But renaming the action methods with AllowAnonymous attribute solves my issue!!
Note: The application runs perfect with authorize attribute when I debug it locally(localhost)
how could I fix this?
startup.cs
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using OnlineExam.Models.LoginModel;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.Authorization;
using OnlineExam.Models.CandidateLogin;
namespace OnlineExam
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
//services.AddControllersWithViews();
services.AddEntityFrameworkSqlServer();
services.AddIdentity<OnlineExam.Models.UserAccountModel.ApplicationUser, IdentityRole>(options =>
{
options.User.AllowedUserNameCharacters = default;
options.User.RequireUniqueEmail = false;
})
.AddEntityFrameworkStores<Models.UserAccountModel.OnlineExamDBContext>();
//services.AddMvc();
services.AddMvc(options =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
options.Filters.Add(new AuthorizeFilter(policy));
});
services.AddDbContext<OnlineExamDBContext>(options => options.UseSqlServer(Configuration.GetConnectionString("LoginConnection")));
services.AddDbContext<OnlineExam.Models.AdminQuestionModel.OnlineExamDBContext>(options => options.UseSqlServer(Configuration.GetConnectionString("LoginConnection")));
services.AddDbContext<CandidateLoginDBContext>(options => options.UseSqlServer(Configuration.GetConnectionString("LoginConnection")));
services.AddDbContext<OnlineExam.Models.CandidateExam.CandidateExamDBContext>(options => options.UseSqlServer(Configuration.GetConnectionString("LoginConnection")));
services.AddScoped<OnlineExam.Models.UserAccountModel.OnlineExamDBContext>();
//services.AddScoped<OnlineExam.Controllers.AdminQuestionController>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
//if (env.IsDevelopment())
//{
// app.UseDeveloperExceptionPage();
//}
//else
//{
// app.UseExceptionHandler("/Home/Error");
// // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
// app.UseHsts();
//}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
}
}
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using OnlineExam.Models.UserAccountModel;
using System.Web;
using Newtonsoft.Json;
using System.Text.Json;
namespace OnlineExam.Controllers
{
[AllowAnonymous]
public class UserAccountsController : Controller
{
private readonly OnlineExamDBContext _context;
private readonly UserManager<OnlineExam.Models.UserAccountModel.ApplicationUser> _userManager;
private readonly SignInManager<OnlineExam.Models.UserAccountModel.ApplicationUser> _signInManager;
List<ApplicationUser> userList = new List<ApplicationUser>();
public UserAccountsController(OnlineExamDBContext context, UserManager<OnlineExam.Models.UserAccountModel.ApplicationUser> userManager, SignInManager<OnlineExam.Models.UserAccountModel.ApplicationUser> signInManager)
{
_context = context;
_userManager = userManager;
_signInManager = signInManager;
}
// GET: UserAccounts
public async Task<IActionResult> Index()
{
return View(await _context.ApplicationUser.ToListAsync());
}
// GET: UserAccounts/Details/5
public async Task<IActionResult> Details(int? id)
{
if (id == null)
{
return NotFound();
}
var userAccount = await _context.ApplicationUser
.FirstOrDefaultAsync(m => m.UserAccountId == id);
if (userAccount == null)
{
return NotFound();
}
return View(userAccount);
}
// GET: UserAccounts/Create
[HttpGet]
public IActionResult Create()
{
var viewmodel = new ApplicationUser();
return View(viewmodel);
}
// POST: UserAccounts/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(ApplicationUser userModel)
{
if (ModelState.IsValid)
{
bool userCheck = IsUserExists(userModel.UserName);
if (userCheck == false)
{
var user = new OnlineExam.Models.UserAccountModel.ApplicationUser();
user = userModel;
var result = await _userManager.CreateAsync(user, userModel.UserPassword);
if (result.Succeeded)
{
return Logout();
}
else
{
foreach (var error in result.Errors)
{
ModelState.AddModelError("", error.Description);
}
}
}
else
{
ModelState.AddModelError("","Username already exist");
}
}
return View(userModel);
}
// GET: UserAccounts/Edit/5
public async Task<IActionResult> Edit(int? id)
{
if (id == null)
{
return NotFound();
}
var userAccount = await _context.ApplicationUser.FindAsync(id);
if (userAccount == null)
{
return NotFound();
}
return View(userAccount);
}
// POST: UserAccounts/Edit/5
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, [Bind("UserAccountId,UserName,UserPassword,UserFullName,UserGender,UserPriviledge,UserDesignation,UserDepartment,UserMailId,UserAddress,UserMobileNo,UserPhoto,UserQualification")] UserAccount userAccount)
{
if (id != userAccount.UserAccountId)
{
return NotFound();
}
if (ModelState.IsValid)
{
try
{
_context.Update(userAccount);
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!UserAccountExists(userAccount.UserAccountId))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToAction(nameof(Index));
}
return View(userAccount);
}
// GET: UserAccounts/Delete/5
public async Task<IActionResult> Delete(int? id)
{
if (id == null)
{
return NotFound();
}
var userAccount = await _context.ApplicationUser
.FirstOrDefaultAsync(m => m.UserAccountId == id);
if (userAccount == null)
{
return NotFound();
}
return View(userAccount);
}
// POST: UserAccounts/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> DeleteConfirmed(int id)
{
var userAccount = await _context.ApplicationUser.FindAsync(id);
_context.ApplicationUser.Remove(userAccount);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
private bool UserAccountExists(int id)
{
return _context.ApplicationUser.Any(e => e.UserAccountId == id);
}
[AllowAnonymous]
[HttpGet]
public IActionResult Login()
{
return View();
}
[AllowAnonymous]
[HttpPost]
public async Task<IActionResult> Login(ApplicationUser login)
{
///var user = new OnlineExam.Models.UserAccountModel.ApplicationUser { UserName = login.UserName };
//TempData["user"] = user;
var result = await _signInManager.PasswordSignInAsync(login.UserName, login.UserPassword, true, false);
if (result.Succeeded)
{
var userData = from x in _context.ApplicationUser.Where(x => x.UserName == login.UserName).ToList()
select new { x.UserFullName, x.Email, x.UserAddress ,x.UserName
,x.UserPhoto ,x.UserMobileNo,x.UserGender,x.UserQualification,
x.UserDepartment,x.UserDesignation,x.UserPriviledge,x.UserAccountId};
//List<ApplicationUser> userList = new List<ApplicationUser>();
foreach (var item in userData)
{
userList.Add(new ApplicationUser
{ UserFullName =item.UserFullName, UserAccountId= item.UserAccountId,UserName=item.UserName,
Email=item.Email,UserDepartment=item.UserDepartment,UserGender=item.UserGender,
UserPriviledge=item.UserPriviledge, UserPhoto=item.UserPhoto, UserAddress=item.UserAddress
});
//userList.Add(new ApplicationUserReplica { UserAccountId = item.UserAccountId });
}
//List<ApplicationUserReplica> userList= new List<ApplicationUserReplica>();
//userList.Add(new ApplicationUserReplica { UserFullName = userData.Select(x => x.UserFullName).ToString()});
// userList.Add(new ApplicationUserReplica { UserAccountId =Convert.ToInt32(userData.Select(x => x.UserAccountId)) });
var sdata=JsonConvert.SerializeObject(userList);
TempData["userData"] = sdata;
return RedirectToAction(nameof(LoginInfo));
}
else
{
ModelState.AddModelError("", "Please enter you username and password correctly");
}
return View(login);
}
public bool IsUserExists(string userName)
{
int c=_context.ApplicationUser.Where(x => x.UserName == userName).Count();
if (c >= 1)
{
return true;
}
else
{
return false;
}
}
[AllowAnonymous]
public ActionResult Logout()
{
_signInManager.SignOutAsync();
return RedirectToAction(nameof(Login));
}
[AllowAnonymous]
[HttpGet]
public IActionResult LoginInfo()
{
userList=JsonConvert.DeserializeObject<List<ApplicationUser>>(TempData["userData"].ToString());
TempData.Keep();
foreach(var item in userList)
{
TempData["userId"] = item.UserAccountId;
}
return View();
}
}
}

Unit Test with Asp.Net Web Api and customer filter

I am working on the Unit Testing in Asp.Net Mvc Web Api.
I have 2 projects
1: Catalog.Api - This contains all the controllers
2: Catalog.UnitTests - This contains the Unit Test for controllers
All Controllers are Inherit with "ApiController" and every controller has custom filter [AuthenticationFilter]. Here is my values controller.
[AuthenticationFilter]
public class ValuesController : ApiController
{
// 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)
{
}
// PUT api/values/5
public void Put(int id, [FromBody]string value)
{
}
// DELETE api/values/5
public void Delete(int id)
{
}
}
And my custom is check the authorization token. Here it is
public class AuthenticationFilter: AuthorizationFilterAttribute
{
public override void OnAuthorization(HttpActionContext actionContext)
{
var request = actionContext.Request;
var authorization = request.Headers.Authorization;
if (authorization == null || authorization.Scheme != "Bearer")
{
ShowAuthenticationError(actionContext, "Authorization required");
return;
}
if (string.IsNullOrEmpty(authorization.Parameter))
{
ShowAuthenticationError(actionContext, "Missing Jwt Token");
return;
}
var token = authorization.Parameter;
var principal = AuthenticateToken(token);
if (principal == null)
{
ShowAuthenticationError(actionContext, "Invalid token");
return;
}
base.OnAuthorization(actionContext);
}
private static void ShowAuthenticationError(HttpActionContext filterContext, string message)
{
var responseDTO = new ResponseDTO() { Code = 401, Message = message };
filterContext.Response =
filterContext.Request.CreateResponse(HttpStatusCode.Unauthorized, responseDTO);
}
}
public class ResponseDTO
{
public int Code { get; set; }
public string Message { get; set; }
}
Now in the Unit Test project i have a class and unit test method.
[TestMethod]
public void CheckFilter()
{
try
{
var controller = new ValuesController();
var controllerContext = new HttpControllerContext();
var request = new HttpRequestMessage();
request.Headers.Add("Authorization", "bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6InVhbGkiLCJlbWFpbCI6InVhbGlAaW5yZWFjaGNlLmNvbSIsIm5iZiI6MTU2NDY0NjIyMSwiZXhwI");
controllerContext.Request = request;
controller.ControllerContext = controllerContext;
var result = controller.Get();
Assert.IsTrue(result.Any());
}
catch (Exception ex)
{
Assert.Fail();
}
}
I am calling my controller by adding reference of API project into my unit test project. So all controllers are available in the unit test project.
Issue is that when i call the values controller it always return the data. And when i remove the request and header so it is also returning the data but in that case that will be unauthorized.
I think my custom filter is not calling. How should that would be called and authenticate the user.
I check your question and configure that issue it is basically you are calling the controller directly.
Basically controller is a class and when you are calling that it is behaving like a simple class and call the method and send back the result. It is simple and clear
But in your situation you have project for your api so can do this.
[TestMethod]
public void CheckFilter()
{
try
{
var config = new HttpConfiguration();
// This is the resgister method which is written in you Api project. That code is after this method this method because i did the same thing to call my controller.
Catalog.Api.WebApiConfig.Register(config);
using (var server = new HttpServer(config))
{
var client = new HttpClient(server);
string url = "http://localhost:PortNumberOfProject/api/values";
var request = new HttpRequestMessage
{
RequestUri = new Uri(url),
Method = HttpMethod.Get
};
request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", "Your Token");
var response = await client.SendAsync(request);
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
}
}
catch (Exception ex)
{
Assert.Fail();
}
}
Here is the WebApi Register method of Api project which is used to register the Api and Routes.
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
var cors = new EnableCorsAttribute("*", "*", "*");
config.EnableCors(cors);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
Here is your controller as it is. And now debug your test and add a break point in your [AuthenticationFilter] and OnAuthorization method.
[AuthenticationFilter]
public class ValuesController : ApiController
{
// GET api/values
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
}

put operations CRUD on a single file in asp.net

**Hello
I am developing an application with ASP.NET API, i created the controller entity and the MVC controllers that my generated CRUD operations in the view as follows (see picture), each operation in a file how to put it all in a single file.
**
enter image description here
controller code:
// GET: /Clients/
public ActionResult Index()
{
return View(db.CLIENT.ToList());
}
// GET: /Clients/Details/5
public ActionResult Details(long? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Client_H Client_H = db.Client_H.Find(id);
if (Client_H == null)
{
return HttpNotFound();
}
return View(Client_H);
}
// GET: /Clients/Create
public ActionResult Create()
{
return View();
}
// POST: /Clients/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include="ID,nom,prenom,CODE,ADRESSE,BQE_VILLE,ADRESSE,TEL")] Client_H Client_H)
{
if (ModelState.IsValid)
{
db.Client_H.Add(Client_H);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(Client_H);
}
// GET: /Clients/Edit/5
public ActionResult Edit(long? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Client_H Client_H = db.Client_H.Find(id);
if (Client_H == null)
{
return HttpNotFound();
}
return View(Client_H);
}
// POST: /Clients/Edit/5
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include="ID,nom,prenom,CODE,ADRESSE,BQE_VILLE,ADRESSE,TEL")] Client_H Client_H)
{
if (ModelState.IsValid)
{
db.Entry(Client_H).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(Client_H);
}
// GET: /Clients/Delete/5
public ActionResult Delete(long? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Client_H Client_H = db.Client_H.Find(id);
if (Client_H == null)
{
return HttpNotFound();
}
return View(Client_H);
}
// POST: /Clients/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public ActionResult DeleteConfirmed(long id)
{
Client_H Client_H = db.Client_H.Find(id);
db.Client_H.Remove(Client_H);
db.SaveChanges();
return RedirectToAction("Index");
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
db.Dispose();
}
base.Dispose(disposing);
}
}
Thank you in advance
I do not understand well what do you mean by "how to put it all in a single file"?
If you want to have all CRUD function in on 1 view, you can use jquery POST & GET.
https://api.jquery.com/jquery.post/
https://api.jquery.com/jquery.get/

Migrating to the WebApi 2.2 RC and getting Response Status 406 (not acceptable)

I migrated to the WebAPI 2.2 RC (Microsoft.AspNet.WebApi -Version 5.2.0-rc) and I since them I get only 406 (Not Acceptable) as status response on all my queries, for example:
http://localhost:7923/api/Quotes(1)
OData Service Configuration
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
config.EnableSystemDiagnosticsTracing();
config.MapODataServiceRoute("api", "api", CreateEdmModel());
}
private static IEdmModel CreateEdmModel()
{
var odataModelBuilder = new ODataConventionModelBuilder();
odataModelBuilder.EntitySet<Tag>("Tags");
odataModelBuilder.EntitySet<Author>("Authors");
EntitySetConfiguration<Quote> quoteEntitySetConfiguration = odataModelBuilder.EntitySet<Quote>("Quotes");
FunctionConfiguration getQuotesRandomFunction = quoteEntitySetConfiguration.EntityType.Collection.Function("Random");
getQuotesRandomFunction.Parameter<int>("count");
getQuotesRandomFunction.ReturnsCollectionFromEntitySet<Quote>("Quotes");
return odataModelBuilder.GetEdmModel();
}
}
QuotesController
public class QuotesController : ODataController
{
private WhatAQuoteDb db = new WhatAQuoteDb();
[ODataRoute("Default.Random(count={count})")]
[EnableQuery]
public IHttpActionResult GetQuotesRandom(int count)
{
return Ok(db.Quotes.OrderBy(quote => Guid.NewGuid()).Take(count));
}
// GET: odata/Quotes
[EnableQuery]
public IQueryable<Quote> GetQuotes()
{
return db.Quotes;
}
// GET: odata/Quotes(5)
[EnableQuery]
public SingleResult<Quote> GetQuote([FromODataUri] int key)
{
return SingleResult.Create(db.Quotes.Where(quote => quote.Id == key));
}
// PUT: odata/Quotes(5)
public async Task<IHttpActionResult> Put([FromODataUri] int key, Quote quote)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
if (key != quote.Id)
{
return BadRequest();
}
db.Entry(quote).State = EntityState.Modified;
try
{
await db.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!QuoteExists(key))
{
return NotFound();
}
else
{
throw;
}
}
return Updated(quote);
}
// POST: odata/Quotes
public async Task<IHttpActionResult> Post(Quote quote)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
db.Quotes.Add(quote);
await db.SaveChangesAsync();
return Created(quote);
}
// PATCH: odata/Quotes(5)
[AcceptVerbs("PATCH", "MERGE")]
public async Task<IHttpActionResult> Patch([FromODataUri] int key, Delta<Quote> patch)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
Quote quote = await db.Quotes.FindAsync(key);
if (quote == null)
{
return NotFound();
}
patch.Patch(quote);
try
{
await db.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!QuoteExists(key))
{
return NotFound();
}
else
{
throw;
}
}
return Updated(quote);
}
// DELETE: odata/Quotes(5)
public async Task<IHttpActionResult> Delete([FromODataUri] int key)
{
Quote quote = await db.Quotes.FindAsync(key);
if (quote == null)
{
return NotFound();
}
db.Quotes.Remove(quote);
await db.SaveChangesAsync();
return StatusCode(HttpStatusCode.NoContent);
}
// GET: odata/Quotes(5)/Author
[EnableQuery]
public SingleResult<Author> GetAuthor([FromODataUri] int key)
{
return SingleResult.Create(db.Quotes.Where(m => m.Id == key).Select(m => m.Author));
}
// GET: odata/Quotes(5)/Tags
[EnableQuery]
public IQueryable<Tag> GetTags([FromODataUri] int key)
{
return db.Quotes.Where(m => m.Id == key).SelectMany(m => m.Tags);
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
db.Dispose();
}
base.Dispose(disposing);
}
private bool QuoteExists(int key)
{
return db.Quotes.Count(e => e.Id == key) > 0;
}
}
I checked your solution and found that you used service reference.
However adding service reference doesn't support OData V4 and the version in your generated code is V3.
You can try OData T4 code generator to generate client code.
Check the blog below:
http://blogs.msdn.com/b/odatateam/archive/2014/03/11/how-to-use-odata-client-code-generator-to-generate-client-side-proxy-class.aspx
Update:
I checked your solution again and found the problem:
The ODataController you used is V3!
If you want the V4 version, you need to change the using namespace in your controller cs file
From
using System.Web.Http.OData;
To
using System.Web.OData;
What is more, there is other problem that the following template is invalid when I start up the project.
[ODataRoute("Default.Random(count={count})")]
I guest that the random function you defined is a function import and you should define like this:
FunctionConfiguration getQuotesRandomFunction = odataModelBuilder.Function("Random");
And the function import should not add namespace and the template should be:
[ODataRoute("Random(count={count})")]
Let me know if you have other problems.

The resource cannot be found Error

This error comes to me.
The resource cannot be found.
Description: HTTP 404. The resource you are looking for (or one of its dependencies) could have been removed, had its name changed, or is temporarily unavailable. Please review the following URL and make sure that it is spelled correctly.
Requested URL: /Dinner
I searched but there is not suitable answers for me.
The spell of my controller is correct. I tried and checked many times.
I did not customize my rounting Globle.asax
I checked the "Web" tab under my project's properties, the "SpecificPage is tickled without any contents"
Everything is by default. Anyway here is the default code for rounting. Who knows why?Thanks
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
}
Here is my Dinner controller
namespace NerdDinner.Controllers
{
public class DinnerController : Controller
{
IDinnerRepository _repository;
public DinnerController()
{
_repository = new sqlDinnerRepository();
}
public DinnerController(IDinnerRepository repository)
{
_repository = repository;
}
//
// GET: /Dinner/
public ActionResult Index()
{
var dinners = _repository.FindAllDinners();
return View(dinners);
}
//
// GET: /Dinner/Details/5
public ActionResult Details(int id)
{
var dinner = _repository.GetDinner(id);
return View(dinner);
}
//
// GET: /Dinner/Create
public ActionResult Create()
{
return View();
}
//
// POST: /Dinner/Create
[HttpPost]
public ActionResult Create(Dinner dinner)
{
try
{
// TODO: Add insert logic here
_repository.AddDinner(dinner);
_repository.UpdateDinner(dinner);
return RedirectToAction("Index");
}
catch
{
return View(dinner);
}
}
//
// GET: /Dinner/Edit/5
public ActionResult Edit(int id)
{
var dinner = _repository.GetDinner(id);
return View(dinner);
}
//
// POST: /Dinner/Edit/5
[HttpPost]
public ActionResult Edit(int id, FormCollection collection)
{
var dinner = _repository.GetDinner(id);
try
{
// TODO: Add update logic here
UpdateModel(dinner, collection.ToValueProvider());
_repository.UpdateDinner(dinner);
return RedirectToAction("Index");
}
catch
{
return View(dinner);
}
}
//
// POST: /Dinner/Delete/5
[HttpPost]
public ActionResult Delete(int id)
{
var db = new dbDataContext();
var dinner = db.Dinners.SingleOrDefault(x => x.DinnerID == id);
try
{
// TODO: Add delete logic here
_repository.DeleteDinner(dinner);
_repository.UpdateDinner(dinner);
return RedirectToAction("Index");
}
catch
{
return View(dinner);
}
}
}
}
Here is IDinnerRepository interface
namespace NerdDinner.Models
{
interface IDinnerRepository
{
IQueryable<Dinner> FindAllDinners();
Dinner GetDinner(int id);
void AddDinner(Dinner dinner);
void UpdateDinner(Dinner dinner);
void DeleteDinner(Dinner dinner);
}
}
sqlDinnerRepository class implements IDinnerRepository interface
namespace NerdDinner.Models
{
public class sqlDinnerRepository
{
dbDataContext db;
public sqlDinnerRepository()
{
db = new dbDataContext();
}
public IQueryable<Dinner> FindAllDinners()
{
return db.Dinners;
}
public Dinner GetDinner(int id)
{
return db.Dinners.SingleOrDefault(x => x.DinnerID == id);
}
public void AddDinner(Dinner dinner)
{
db.Dinners.InsertOnSubmit(dinner);
}
public void UpdateDinner(Dinner dinner)
{
db.SubmitChanges();
}
public void DeleteDinner(Dinner dinner)
{
db.Dinners.DeleteOnSubmit(dinner);
}
}
}
I type "http://localhost:52372/Dinner" in my browser.

Resources