I'm creating a web api controller and implement ([HttpGet])parameterized get method with datatype class but when I run this its show 404 Not Found.
When i am implementing normal datatype like string or int its show me the answer or datatype like List still it's giving me answer but when I directly declare datatype as class like Student its show 404 not found error. I don't know why it's so. I am trying to learn web api with mvc please help me.
I am creating one simple class Student and one studentapicontroller.In my api controller, I create get method with datatype class and for testing purpose i make other get method with different datatype
Student.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace epay.Models
{
public class student
{
public int id { get; set; }
public string name { get; set; }
}
}
studentapiController :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using epay.Models;
namespace epay.Controllers
{
public class studentapiController : ApiController
{
// GET api/studentapi
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
// GET api/studentapi/5
{
return "value";
}
// POST api/studentapi
public void Post([FromBody]string value)
{
}
// PUT api/studentapi/5
public void Put(int id, [FromBody]string value)
{
}
// DELETE api/studentapi/5
public void Delete(int id)
{
}
//POST api/studentapi/
[HttpGet]
public student getdetails(int id, string na)
{
student st = new student();
st.id = id;
st.name = na;
return st;
}
//GET api/studentapi/getstud
[HttpGet]
public List<student> getstud()
{
List<student> lst = new List<student>();
student st = new student();
st.name = "manlai";
st.id = 5;
lst.Add(st);
return lst;
}
}
}
I just want getdetails result or how to do if I want my method datatype as a class and I am passing parameter with my get method how to do this
Make getdetails route like below because it is conflicting with get
[HttpGet("getdetails")]
public student getdetails(int id, string na)
{
student st = new student();
st.id = id;
st.name = na;
return st;
}
you can call route something like this with querystring /studentapi/getdetails?id=1&na=test
Related
I have coded RestAPI with .NET . I am using Postman to test the API.
It is giving me successful http request for GET and DELETE. But throwing error for PUT and POST request.
Below are the codes I am using to create RestAPI.
Code: Player.cs
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace UnityRestAPI.Contracts
{
[JsonObject, Serializable]
public class Player
{
public int Id { get; set; }
public string FullName { get; set; }
public float Score { get; set; }
}
}
Code: PlayersController.cs
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Mvc;
using UnityRestAPI.Contracts;
namespace UnityRestAPI.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class PlayersController : Controller
{
private static List<Player> Players = new List<Player>()
{
new Player
{
Id = 1,
FullName = "Michael Jordan",
Score = 1000
},
new Player
{
Id = 2,
FullName = "Steve Jobs",
Score = 2000
},
new Player
{
Id = 3,
FullName = "Carton John",
Score = 3000
},
};
// GET api/players
[HttpGet]
public JsonResult Get()
{
return Json(Players);
}
// GET api/players/5
[HttpGet("{id}")]
public JsonResult Get(int id)
{
Player player = Players.Single(p => p.Id == id);
return Json(player);
}
// POST api/players
[HttpPost]
public JsonResult Post([FromBody]Player newPlayer)
{
Players.Add(newPlayer);
return Json(Players);
}
// PUT api/players/5
[HttpPut("{id}")]
public JsonResult Put(int id, [FromBody] float newScore)
{
Player player = Players.Single(p => p.Id == id);
player.Score = newScore;
return Json(player);
}
// DELETE api/players/5
[HttpDelete("{id}")]
public void Delete(int id)
{
Player player = Players.Single(p => p.Id == id);
Players.Remove(player);
}
}
}
RestAPI GET request in Postman:
Successful request
Postman Error for POST request in Postman:
Input not valid
its a RAW Type issue
try to Change the following
To
In my project (Asp.net MVC), I want to use DevExtreme GridView to display my data. I've used code first to create databases and tables. In the project, I have a model with the name of Member. I did right click on the Controller folder and select Add->Controller->DevExtreme Web API Controller with actions, using Entity Framework. In the wizard, I selected my database context and model and determine my controller name (MembersController) and then clicked Add. So in the Views folder, I created a folder with name Members and inside it, I added a view with name Index. (I don't know what exactly name must be for view, you suppose Index). In the index view, I used the wizard to add a DevExtreme GridView (Right-click on the view context and click on Insert A DevExtreme Control Here. In the wizard, I selected GridView as control and DatabaseContext, Member model and Members controller. You can see all of my codes in the below:
Member Mode:
Model:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace WebApplication2.Models
{
public class Member
{
#region Ctor
public Member()
{
}
#endregion
#region Properties
[Key]
public int MemberID { get; set; }
[Required(ErrorMessage ="*")]
public string FirstName { get; set; }
[Required(ErrorMessage = "*")]
public string LastName { get; set; }
public string Phone { get; set; }
public string Mobile { get; set; }
[Required(ErrorMessage = "*")]
public string NID { get; set; }
[Required(ErrorMessage = "*")]
public string MID { get; set; }
[Required(ErrorMessage = "*")]
public string SalaryID { get; set; }
#endregion
}
}
Controller:
[Route("api/Members/{action}", Name = "MembersApi")]
public class MembersController : ApiController
{
private ApplicationDbContext _context = new ApplicationDbContext();
[HttpGet]
public HttpResponseMessage Get(DataSourceLoadOptions loadOptions) {
var members = _context.Members.Select(i => new {
i.MemberID,
i.FirstName,
i.LastName,
i.Phone,
i.Mobile,
i.NID,
i.MID,
i.SalaryID
});
return Request.CreateResponse(DataSourceLoader.Load(members, loadOptions));
}
[HttpPost]
public HttpResponseMessage Post(FormDataCollection form) {
var model = new Member();
var values = JsonConvert.DeserializeObject<IDictionary>(form.Get("values"));
PopulateModel(model, values);
Validate(model);
if (!ModelState.IsValid)
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, GetFullErrorMessage(ModelState));
var result = _context.Members.Add(model);
_context.SaveChanges();
return Request.CreateResponse(HttpStatusCode.Created, result.MemberID);
}
[HttpPut]
public HttpResponseMessage Put(FormDataCollection form) {
var key = Convert.ToInt32(form.Get("key"));
var model = _context.Members.FirstOrDefault(item => item.MemberID == key);
if(model == null)
return Request.CreateResponse(HttpStatusCode.Conflict, "Member not found");
var values = JsonConvert.DeserializeObject<IDictionary>(form.Get("values"));
PopulateModel(model, values);
Validate(model);
if (!ModelState.IsValid)
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, GetFullErrorMessage(ModelState));
_context.SaveChanges();
return Request.CreateResponse(HttpStatusCode.OK);
}
[HttpDelete]
public void Delete(FormDataCollection form) {
var key = Convert.ToInt32(form.Get("key"));
var model = _context.Members.FirstOrDefault(item => item.MemberID == key);
_context.Members.Remove(model);
_context.SaveChanges();
}
private void PopulateModel(Member model, IDictionary values) {
string MEMBER_ID = nameof(Member.MemberID);
string FIRST_NAME = nameof(Member.FirstName);
string LAST_NAME = nameof(Member.LastName);
string PHONE = nameof(Member.Phone);
string MOBILE = nameof(Member.Mobile);
string NID = nameof(Member.NID);
string MID = nameof(Member.MID);
string SALARY_ID = nameof(Member.SalaryID);
if(values.Contains(MEMBER_ID)) {
model.MemberID = Convert.ToInt32(values[MEMBER_ID]);
}
if(values.Contains(FIRST_NAME)) {
model.FirstName = Convert.ToString(values[FIRST_NAME]);
}
if(values.Contains(LAST_NAME)) {
model.LastName = Convert.ToString(values[LAST_NAME]);
}
if(values.Contains(PHONE)) {
model.Phone = Convert.ToString(values[PHONE]);
}
if(values.Contains(MOBILE)) {
model.Mobile = Convert.ToString(values[MOBILE]);
}
if(values.Contains(NID)) {
model.NID = Convert.ToString(values[NID]);
}
if(values.Contains(MID)) {
model.MID = Convert.ToString(values[MID]);
}
if(values.Contains(SALARY_ID)) {
model.SalaryID = Convert.ToString(values[SALARY_ID]);
}
}
private string GetFullErrorMessage(ModelStateDictionary modelState) {
var messages = new List<string>();
foreach(var entry in modelState) {
foreach(var error in entry.Value.Errors)
messages.Add(error.ErrorMessage);
}
return String.Join(" ", messages);
}
protected override void Dispose(bool disposing) {
if (disposing) {
_context.Dispose();
}
base.Dispose(disposing);
}
}
View:
#{
Layout = "~/Views/Shared/_Layout.cshtml";
}
#(Html.DevExtreme().DataGrid<WebApplication2.Models.Member>()
.DataSource(ds => ds.WebApi()
.RouteName("MembersApi")
.LoadAction("Get")
.InsertAction("Post")
.UpdateAction("Put")
.DeleteAction("Delete")
.Key("MemberID")
)
.RemoteOperations(true)
.Columns(columns => {
columns.AddFor(m => m.MemberID);
columns.AddFor(m => m.FirstName);
columns.AddFor(m => m.LastName);
columns.AddFor(m => m.Phone);
columns.AddFor(m => m.Mobile);
columns.AddFor(m => m.NID);
columns.AddFor(m => m.MID);
columns.AddFor(m => m.SalaryID);
})
.Editing(e => e
.AllowAdding(true)
.AllowUpdating(true)
.AllowDeleting(true)
)
)
WebApiConfig.cs file:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;
namespace WebApplication2
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
// WebAPI when dealing with JSON & JavaScript!
// Setup json serialization to serialize classes to camel (std. Json format)
var formatter = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
formatter.SerializerSettings.ContractResolver =
new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver();
}
}
}
Global.asax.cs file:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
namespace WebApplication2
{
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
}
}
In addition I've installed all requirements for this project according this link.
But when I try to show View with https://localhost:44328/Members/index RUL, I get this error:
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: /Members/index
I'v tried a lot way to correct my wrong but I couldn't find solution. I almost read all of documents about routing (mvc and web api), but after about 5 days I still couldn't to solve it.
Thanks a lot for answer me.
The thing is as far as I can tell, one of the reasons you are receiving a 404 is because you don't seem to be adding your parameter anywhere. Aside from that your 'DataSourceLoadOptions loadOptions' shouldn't be used as a parameter because it is probably too complex. Shouldn't you create a service which retrieves your loadOptions instead of you giving it along?
If you want all members without giving information then you should do exactly that. Not give the request some metadata it doesn't know about along for the ride.
I suggest you do the following:
Create an API which does not need metadata like how to get a datasource. Things such as Members.LastName are acceptable
Make sure you create a service which is responsible for getting your data in the first place. This means also removing all that extra code in your controller and placing it in a more suitable location.
Keep your classes clean and simple. Your controller now has too many responsibilities.
Hopefully this'll help. If you try your API GET Method as is without the 'DataSourceLoadOptions loadOptions' parameter, then your API will not return 404.
Since you didn't put in your ajax call url, I'm going to have to work with this
Requested URL: /Members/index
This is a problem, your webApi default route requires your URL to be prepended with /api/
So something like this should work /api/Members, so you can remove the Index part of that URL as the request type will handle which Action is executed ie HTTPGet/HTTPPost
EDIT: Use this as your route
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { controller = "Members" id = RouteParameter.Optional }
);
I have the following FitNesse test implemented against .NET. It uses "RowFixture" to return an object which is verified. All this works ok.
My Question is, how can I pass the "inputs" to the array from the FIT test?
At the monent, this is hard coded internally.
Here is the FIT test:
!|ReturnObjectMultiDimension|
|Id |Name |
|1, 2, 3, 4 |a, b, c, d |
Here is the code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using fit;
using dbfit;
namespace DbFitProject
{
public class ReturnObjectMultiDimension : RowFixture
{
public override Type GetTargetClass()
{
return typeof(CustomerObject);
}
public override object[] Query()
{
CustomerObject[] array = new CustomerObject[1];
array[0] = new CustomerObject(new int[4] { 1, 2, 3, 4 }, new string[4] {"a","b","c","d" });
return array;
}
}
public class CustomerObject
{
public int[] Id;
public string[] Name;
public CustomerObject(int[] Id, string[] Name)
{
this.Id = Id;
this.Name = Name;
}
}
}
Thanks for help.
It's simpler to just have a class that creates a customer object list and fitSharp will automatically wrap the list in a fixture to check the results:
public class MyClass {
public List<CustomerObject> MakeListWithIdsNames(int[] ids, string[] names) {
return new List<CustomerObject> { new CustomerObject(ids, names) };
}
}
|my class|
|make list with ids|1,2,3,4|names|a,b,c,d|
|id|name|
|1,2,3,4|a,b,c,d|
See http://fitsharp.github.io/Fit/FixtureWrapper.html
I have a simple database with five tables bound together by relationships. I've built OData apps before and like the model, but wanted to make the leap to Web API. The problem is - when I make my call to the ProductType table for example - it returns EVERY record in every table! What gives?
My goal is to call a ProductType for example like this:
url/api/ProductType
(and the usual getbyId, delete, etc)
I'm using the repository pattern, and following these steps:
1. Create a Entity Framework model with the tables I want to display. Yawn.
2. Add an interface in Models, call it IProductTypeRepository, with the behaviors I want to see.
3. Add a model class (ProductModel.cs) that inherits from this interface
4. Make sure Global.asax has either default api setup or there’s a App_Start\Routeconfig and WebApiConfig class.
5. Surgery on the ValuesController class.
Maybe this is in ignorance of how WebAPI is supposed to work with relationships. Perhaps the goal is to do one call to a service - and get EVERY record across multiple tables (for example, Product and ProductDetails). If so, I think the documentation could have been a LOT clearer on this point!
============================CODE FOLLOWS!================================================
I’m going to skip the EF auto-generated code obviously – but suffice to say it contains entities and joins for five tables – ProductType, Location, Process, Step, and StepType. ProductType is a very simple table with an ID field and a description and a part # field (MaterialMasterId).
For IProductTypeRepository, here is my code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Perceptive.Services.Models
{
interface IProductTypeRepository
{
IEnumerable<ProductType> GetAll();
ProductType GetById(int ProductTypeID);
int Update(ProductType producttype);
ProductType Add(ProductType producttype);
void Delete(int ProductTypeId);
}
}
For ProducTTypeModel:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace Perceptive.Services.Models
{
public class ProductTypeModel : IProductTypeRepository
{
private PCSEntities1 context = new PCSEntities1();
public IEnumerable<ProductType> GetAll()
{
return context.ProductTypes;
}
public ProductType GetById(int ProductTypeId)
{
IQueryable<ProductType> producttypes = context.ProductTypes.Where(a => a.ProductTypeID == ProductTypeId);
return producttypes.FirstOrDefault();
}
public int Update(ProductType producttype)
{
ProductType updateProductType = context.ProductTypes.FirstOrDefault(c => c.ProductTypeID == producttype.ProductTypeID);
updateProductType.Description = producttype.Description.Trim();
updateProductType.MaterialMasterID = producttype.MaterialMasterID;
return context.SaveChanges();
}
public ProductType Add(ProductType producttype)
{
var addedProductType = context.ProductTypes.Add(producttype);
context.SaveChanges();
return addedProductType;
}
public void Delete(int producttypeid)
{
ProductType producttype = context.ProductTypes.FirstOrDefault(a => a.ProductTypeID == producttypeid);
context.ProductTypes.Remove(producttype);
context.SaveChanges();
}
}
}
… and lastly, my Controller – ProductTypeController.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
//dh added
using Perceptive.Services.Models;
namespace Perceptive.Services.Controllers
{
public class ProductTypeController : ApiController
{
IProductTypeRepository repository = new ProductTypeModel();
// GET /api/Producttype
[HttpGet]
public IEnumerable<ProductType> Get()
{
return repository.GetAll();
}
// GET /api/Producttype/5
[HttpGet]
public ProductType Get(int id)
{
ProductType producttype = repository.GetById(id);
return producttype;
}
// POST /api/ProducTtype
[HttpPost]
public void PostProductType(ProductType producttype)
{
repository.Add(producttype);
}
// PUT /api/ProductType
// DH seems scanty here. Where's the repository put?
[HttpPut]
public void PutProductType(ProductType producttype)
{
if (repository.Update(producttype) == 0)
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
}
//DELETE /api/ProductType/5
[HttpDelete]
public void Delete (int id)
{
repository.Delete(id);
}
}
}
You need to use IQueryable:
interface IProductTypeRepository
{
IQueryable<ProductType> GetAll();
ProductType GetById(int ProductTypeID);
int Update(ProductType producttype);
ProductType Add(ProductType producttype);
void Delete(int ProductTypeId);
}
When you use IEnumerable it is going to pull all the records in the entity client side and then work on them. IQueryable is treated as a query until you call an action like .ToList() which will execute the query and pull the results to the client.
I need help Sir, newbie in MVC, I would like to ask why I can't find
the store DB even it is declared at the bottom.
The "storeDB" does not exist in the current context
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using MyMusicStore.Models;
namespace MyMusicStore.Controllers
{
public class StoreController : Controller
{
//
// GET: /Store/
public ActionResult Index()
{
var genres = storeDB.Genres.ToList();
return View(genres);
}
public ActionResult Browse(string genre)
{
var newGenre = new Genre { Name = genre };
return View (newGenre);
}
public ActionResult Details(int id)
{
var album = new Album { Title = "Album" + id };
return View(album);
}
public class StoreController : Controller
{
MusicStoreEntities storeDB = new MusicStoreEntities();
}
}
}
Inside of the class StoreController, you declare StoreController a second time, and declare the variable inside that. What you've made is what's called an 'inner class', and the inner class is DIFFERENT from the outer class even though it appears to have the same name, it is brand new.
So you meant to do this instead:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using MyMusicStore.Models;
namespace MyMusicStore.Controllers
{
public class StoreController : Controller
{
//
// GET: /Store/
public ActionResult Index()
{
var genres = storeDB.Genres.ToList();
return View(genres);
}
public ActionResult Browse(string genre)
{
var newGenre = new Genre { Name = genre };
return View (newGenre);
}
public ActionResult Details(int id)
{
var album = new Album { Title = "Album" + id };
return View(album);
}
MusicStoreEntities storeDB = new MusicStoreEntities();
}
}