Multiple OData entity GET methods - entity-framework

I've used OData with entity framework to create a simple web service. Everything works fine. I just need to know how to add additional GET commands such as "GetByCategory" or "GetByDate". These will use different SQL views to return complex filtered results.
** WebApiConfig.cs *
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Web.Http;
using Microsoft.Owin.Security.OAuth;
using Newtonsoft.Json.Serialization;
using System.Web.Http.OData.Builder;
using System.Web.Http.OData.Extensions;
using NRHSData.Models;
namespace NRHSData
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Configure Web API to use only bearer token authentication.
config.SuppressDefaultHostAuthentication();
config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
config.AddODataQueryFilter();
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
builder.Namespace = "NRHSData";
builder.EntitySet<employee>("employees");
builder.EntitySet<vw_employee_listing>("vw_employee_listings");
builder.EntitySet<physician>("physicians");
builder.EntitySet<vw_physician_listing>("vw_physician_listings");
builder.EntitySet<employeedepartment>("employeedepartments");
builder.EntitySet<vw_employeedepartment_listing>("vw_employeedepartment_listings");
builder.EntitySet<news>("news");
builder.EntitySet<vw_news_listing>("vw_news_listings");
builder.EntitySet<vw_news_current>("vw_news_current");
config.Routes.MapODataServiceRoute("odata", "odata", builder.GetEdmModel());
}
}
}
** newsController.cs *
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.Http.ModelBinding;
using System.Web.Http.OData;
using System.Web.Http.OData.Routing;
using NRHSData.Models;
namespace NRHSData.Controllers
{
[Authorize]
public class newsController : ODataController
{
private ENTDATAEntities db = new ENTDATAEntities();
// GET: odata/news
[EnableQuery]
public IQueryable<vw_news_listing> Getnews()
{
return db.vw_news_listings;
}
// GET: odata/news(5)
[EnableQuery]
public SingleResult<vw_news_listing> Getnews([FromODataUri] int key)
{
return SingleResult.Create(db.vw_news_listings.Where(news => news.newsid == key));
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
db.Dispose();
}
base.Dispose(disposing);
}
private bool newsExists(int key)
{
return db.news.Count(e => e.newsid == key) > 0;
}
// PUT: odata/news(5)
public async Task<IHttpActionResult> Put([FromODataUri] int key, Delta<news> patch)
{
Validate(patch.GetEntity());
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
news news = await db.news.FindAsync(key);
if (news == null)
{
return NotFound();
}
patch.Put(news);
try
{
await db.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!newsExists(key))
{
return NotFound();
}
else
{
throw;
}
}
return Updated(news);
}
// POST: odata/news
public async Task<IHttpActionResult> Post(news news)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
db.news.Add(news);
await db.SaveChangesAsync();
return Created(news);
}
// PATCH: odata/news(5)
[AcceptVerbs("PATCH", "MERGE")]
public async Task<IHttpActionResult> Patch([FromODataUri] int key, Delta<news> patch)
{
Validate(patch.GetEntity());
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
news news = await db.news.FindAsync(key);
if (news == null)
{
return NotFound();
}
patch.Patch(news);
try
{
await db.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!newsExists(key))
{
return NotFound();
}
else
{
throw;
}
}
return Updated(news);
}
// DELETE: odata/news(5)
public async Task<IHttpActionResult> Delete([FromODataUri] int key)
{
news news = await db.news.FindAsync(key);
if (news == null)
{
return NotFound();
}
db.news.Remove(news);
await db.SaveChangesAsync();
return StatusCode(HttpStatusCode.NoContent);
}
}
}

I assume you are trying to address such requests:
~/News/GetByDate()
There are 2 options:
Using OData Actions. Add an action named GetByDate and issue the Request through 'POST ~/News/GetByDate()' But it does NOT align with the protocol. An Action should have some side effect. So the second option comes.
Using OData Functions, which must not have side effect. To implement this, you need to upgrade to the new bits: System.Web.OData.dll. here is a sample about functions: https://aspnet.codeplex.com/SourceControl/latest#Samples/WebApi/OData/v4/ODataFunctionSample/ .

Related

Error 500 "Internal Server Error" between Flutter App and my BackEnd

I have an error and i tired to look up it and i still not find it.
Scenario: I made my Backend in C# with VS, the FrontEnd is with Flutter.
all my backend works perfectly with all my Flutter App, but there is one problem with only one Action.
When i try to "Save, Update or Delete " a record, it appears the next message in my app, when i put a revision point in my Flutter code in the action to save/delete or update, apperars the CodeError 500 and "Internal Server Error".
The DB is in Azure, and i allready erase and create it twice, and the error persist.
the error is only with this code, the other Ssave/update or delete action.
attach the Images of my code:
Code of The Backend
using System.ComponentModel.DataAnnotations;
namespace Vehicles.API.Models.Request
{
public class HistoryRequest
{
public int Id { get; set; }
[Required(ErrorMessage = "El campo {0} es obligatorio")]
public int VehicleId { get; set; }
[Required(ErrorMessage = "El campo {0} es obligatorio")]
public int Mileage { get; set; }
[Required(ErrorMessage = "El campo {0} es obligatorio")]
public string Remarks { get; set; }
}
}
Other Page, the API Contoller
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using Vehicles.API.Data;
using Vehicles.API.Data.Entities;
using Vehicles.API.Models.Request;
namespace Vehicles.API.Controllers.API
{
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
[Route("api/[controller]")]
[ApiController]
public class HistoriesController : ControllerBase
{
private readonly DataContext _context;
private readonly IUserhelper _userhelper;
public HistoriesController(DataContext context, IUserhelper userhelper)
{
_context = context;
_userhelper = userhelper;
}
[HttpGet("{id}")]
public async Task<ActionResult<History>> GetHistory(int id)
{
History history = await _context.Histories
.Include(x => x.Details)
.ThenInclude(x => x.Procedure)
.FirstOrDefaultAsync(x => x.Id == id);
if (history == null)
{
return NotFound();
}
return history;
}
[HttpPost]
public async Task<ActionResult<History>> PostHistory(HistoryRequest request)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
Vehicle vehicle = await _context.Vehicles.FindAsync(request.VehicleId);
if (vehicle == null)
{
return BadRequest("El Vehiculo no existe");
}
string email = User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier).Value;
User user = await _userhelper.GetUserAsync(email);
if (user == null)
{
return BadRequest("La usuario no existe");
}
History history = new()
{
Date = DateTime.UtcNow,
Details= new List<Detail>(),
Mileage=request.Mileage,
Remarks=request.Remarks,
User=user,
Vehicle=vehicle,
};
_context.Histories.Add(history);
await _context.SaveChangesAsync();
return Ok(history);
}
[HttpPut("{id}")]
public async Task<IActionResult> PutHistory(int id, HistoryRequest request)
{
if (id != request.Id)
{
return BadRequest();
}
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
History history = await _context.Histories.FindAsync(request.Id);
if (history == null)
{
return BadRequest("La historia no existe");
}
history.Mileage = request.Mileage;
history.Remarks= request.Remarks;
_context.Histories.Update(history);
await _context.SaveChangesAsync();
return NoContent();
}
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteHistory(int id)
{
History history = await _context.Histories
.Include(x => x.Details)
.FirstOrDefaultAsync(x => x.Id == id);
if (history == null)
{
return NotFound();
}
_context.Histories.Remove(history);
await _context.SaveChangesAsync();
return NoContent();
}
}
}
Code in VC Flutter:
Response response = await ApiHelper.delete(
'/api/Histories/', widget.history.id.toString(), widget.token);
setState(() {
_showLoader = false;
});
if (!response.isSuccess) {
await showAlertDialog(
context: context,
title: 'Error',
message: response.message,
actions: <AlertDialogAction>[
AlertDialogAction(key: null, label: 'Aceptar'),
]);
return;
}
Navigator.pop(context, 'yes');
}
And the Code of the API code to conect with the backend:
static Future<Response> delete(
String controller, String id, Token token) async {
if (!_validToken(token)) {
return Response(
isSuccess: false,
message:
'Sus Credenciales se han vencido, favor cierre sesion y vuelva a ingresar nuevamente al sistema.');
}
var url = Uri.parse('${Constans.apiUrl}$controller$id');
var response = await http.delete(
url,
headers: {
'content-type': 'application/json',
'accept': 'application/json',
'authorization': 'bearer ${token.token}',
},
);
if (response.statusCode >= 400) {
return Response(isSuccess: false, message: response.body);
}
return Response(isSuccess: true);
}

OData GetById is not working on Asp.net Core 2.2

I am trying to get a single item from my list of elements and it is not working. I am using FromODataUri correctly, I am not seeing what is wrong.
I am able to hit this resource:
https://localhost:44314/odata/Inventories
but I can't get a single item: https://localhost:44314/odata/Inventories(1)
This is how my Startup.cs looks
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNet.OData.Builder;
using Microsoft.AspNet.OData.Extensions;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.OData.Edm;
using OdataTest.Models;
using Swashbuckle.AspNetCore.Swagger;
namespace OdataTest
{
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.AddOData();
services.AddODataQueryFilter();
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new Info { Title = "Inventory Api", Version = "v1" });
});
services.AddMvc(options => options.EnableEndpointRouting = false).SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}
// 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();
}
else
{
// 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.UseSwagger();
app.UseSwaggerUI(c =>
{
// force to add another /swagger to fix issue
c.SwaggerEndpoint("/swagger/v1/swagger.json", "Physical Inventory API");
});
app.UseHttpsRedirection();
app.UseMvc(b =>
b.MapODataServiceRoute("odata", "odata", GetEdmModel(app.ApplicationServices))
);
}
private static IEdmModel GetEdmModel(IServiceProvider serviceProvider)
{
ODataModelBuilder builder = new ODataConventionModelBuilder(serviceProvider);
builder.Namespace = "PartsInventory";
builder.ContainerName = "PartsInventoryContainer";
builder.EntitySet<InventoryOutputDto>("Inventories").EntityType
.Filter()
.Count()
.Expand()
.OrderBy()
.Page()
.Select();
return builder.GetEdmModel();
}
}
}
And my Controller
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNet.OData;
using Microsoft.AspNet.OData.Routing;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using OdataTest.Models;
namespace OdataTest.Controllers
{
public class PartsInventoryController : ODataController
{
List<InventoryOutputDto> list = new List<InventoryOutputDto>() {
new InventoryOutputDto {
Description = "Description1",
UserName = "user1",
EndDate = DateTime.Now,
ErrorId = "Error",
InventoryId = 1,
LocationCode = 1,
StartDate = DateTime.Now,
StatusCode = 1
},
new InventoryOutputDto {
Description = "Description1",
UserName = "user1",
EndDate = DateTime.Now,
ErrorId = "Error2",
InventoryId = 2,
LocationCode = 2,
StartDate = DateTime.Now,
StatusCode = 2
} };
[HttpGet]
[ODataRoute("Inventories")]
/// public IActionResult Inventory(InventoryInputDto inputDto)
public IActionResult GetInventories(InventoryInputDto inputDto)
{
return StatusCode(StatusCodes.Status200OK, list);
}
[HttpGet]
[ODataRoute("Inventories({key})")]
public IActionResult GetInventoryById([FromODataUri] int key)
{
var invRecord = list.FirstOrDefault(i => i.InventoryId == key);
if(invRecord == null)
{
return NotFound();
}
return Ok(invRecord);
}
}
}

Pass ID once to a controller and have all controller methods remember boolean check

I just created a simple web API using .NetCore 2.2 and Entity Framework.
I added a bit of security, by passing in a userID to each controller that the user accesses.
But I noticed that it starts getting messy when I have to add the userID to every controller in my app and the run my user check to make sure the user can access that content.
Below you'll see an example of what I mean.
I'm wondering, is there a way to add it once and then have every controller check for it?
Thanks!
[Route("api/[controller]")]
[ApiController]
public class EngineController : ControllerBase
{
private readonly engineMaker_Context _context;
public EngineController(engineMaker_Context context)
{
_context = context;
}
// GET: api/Engine
[HttpGet("{userID}")]
public async Task<ActionResult<IEnumerable<Engine>>> GetEngine(string userID)
{
if(!CanAccessContent(userID))
{
return Unauthorized();
}
return await _context.Engine.ToListAsync();
}
// GET: api/Engine/123/5
[HttpGet("{userID}/{id}")]
public async Task<ActionResult<Engine>> GetEngine(string userID, string id)
{
if(!CanAccessContent(userID))
{
return Unauthorized();
}
var engine = await _context.Engine.FindAsync(id);
if (engine == null)
{
return NotFound();
}
return engine;
}
// PUT: api/Engine/123/5
[HttpPut("{userID}/{id}")]
public async Task<IActionResult> PutEngine(string userID, string id, Engine engine)
{
if(!CanAccessContent(userID))
{
return Unauthorized();
}
if (id != engine.ObjectId)
{
return BadRequest();
}
_context.Entry(engine).State = EntityState.Modified;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!EngineExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return NoContent();
}
private bool CanAccessContent(string userID)
{
return _context.AllowedUsers.Any(e => e.UserId == userID);
}
}
You could try IAsyncAuthorizationFilter to check the userID.
IAsyncAuthorizationFilter
public class UserIdFilter : IAsyncAuthorizationFilter
{
public Task OnAuthorizationAsync(AuthorizationFilterContext context)
{
var dbContext = context.HttpContext.RequestServices.GetRequiredService<ApplicationDbContext>();
var userId = context.RouteData.Values["userID"] as string;
if (!dbContext.Users.Any(u => u.Email == userId))
{
context.Result = new UnauthorizedResult();
}
return Task.CompletedTask;
}
}
Regiter UserIdFilter for all action.
services.AddMvc(options =>
{
options.Filters.Add(typeof(UserIdFilter));
})
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

Getting Data from HTTP Request Xamarin

I want to get and pass data from my HTTPWebRequest to my sync page. I am new to MVVM so I don't know if I am correct but so far I can check if there is a result. I tried to watch a lots of video tutorials and forums still I can't find what I need. I was hoping you guys have a answer for me. I have been struggling with this for a week now.
The flow of my project:
- The user will login when it is correct, The user will be redirected to my sync page where it will get all the users data from my server and insert the data into SQLite Database.
My questions are:
1. How can I get the data and specific data from my HTTPWebRequest?
2. Is my HTTPWebRequest service correct?
3. Is my MVVM correct?
4. Is my navigation to my next page is correct?
My code:
LoginPage.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TBSMobileApplication.Data;
using TBSMobileApplication.ViewModel;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace TBSMobileApplication.View
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class LoginPage : ContentPage
{
public LoginPageViewModel loginModel;
public LoginPage ()
{
InitializeComponent ();
BindingContext = new LoginPageViewModel();
MessagingCenter.Subscribe<LoginPageViewModel,string>(this, "Login Alert", (sender,Username) =>
{
DisplayAlert("Login Error", "Please fill-up the form", "Ok");
});
MessagingCenter.Subscribe<LoginPageViewModel, string>(this, "Connected", (sender, Username) =>
{
DisplayAlert("Connection Info", "Connected", "Ok");
});
MessagingCenter.Subscribe<LoginPageViewModel, string>(this, "Not Connected", (sender, Username) =>
{
DisplayAlert("Connection Info", "Not Connected", "Ok");
});
MessagingCenter.Subscribe<LoginPageViewModel, string>(this, "Http", (sender, Username) =>
{
DisplayAlert("Login Error", "Username or Password is incorrect", "Ok");
});
entUsername.Completed += (object sender, EventArgs e) =>
{
entPassword.Focus();
};
}
protected async Task OnAppearingAsync()
{
var db = DependencyService.Get<ISQLiteDB>();
var conn = db.GetConnection();
if (conn != null)
{
await conn.CreateTableAsync<UserTable>();
await conn.CreateTableAsync<RetailerTable>();
await conn.CreateTableAsync<ContactsTable>();
}
base.OnAppearing();
}
}
}
LoginPageViewModel.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Net;
using System.Text;
using System.Windows.Input;
using TBSMobileApplication.View;
using Xamarin.Essentials;
using Xamarin.Forms;
namespace TBSMobileApplication.ViewModel
{
public class LoginPageViewModel : INotifyPropertyChanged
{
void OnProperyChanged(string PropertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PropertyName));
}
public string username;
public string password;
public string Username
{
get { return username; }
set
{
username = value;
OnProperyChanged(nameof(Username));
}
}
public string Password
{
get { return password; }
set
{
password = value;
OnProperyChanged(nameof(Password));
}
}
public ICommand LoginCommand { get; set; }
public LoginPageViewModel()
{
LoginCommand = new Command(OnLogin);
}
public void OnLogin()
{
if (string.IsNullOrEmpty(Username) || string.IsNullOrEmpty(Password))
{
MessagingCenter.Send(this, "Login Alert", Username);
}
else
{
var current = Connectivity.NetworkAccess;
if (current == NetworkAccess.Internet)
{
var link = "http://192.168.1.25:7777/TBS/test.php?User=" + Username + "&Password=" + Password;
var request = HttpWebRequest.Create(string.Format(#link));
request.ContentType = "application/json";
request.Method = "GET";
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
{
if (response.StatusCode != HttpStatusCode.OK)
{
Console.Out.WriteLine("Error fetching data. Server returned status code: {0}", response.StatusCode);
}
else
{
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
var content = reader.ReadToEnd();
if (content.Equals("[]") || string.IsNullOrWhiteSpace(content) || string.IsNullOrEmpty(content))
{
MessagingCenter.Send(this, "Http", Username);
}
else
{
App.Current.MainPage.Navigation.PushAsync(new DatabaseSyncPage(), true);
}
}
}
}
}
else
{
MessagingCenter.Send(this, "Not Connected", Username);
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
}

OData V4 REST using GUID primary key

all! I am using OData v4 building REST services. My tables have a GUID primary key.
My GET and POST requests are working fine. But the PUT, PATCH, and DELETE requests fail with 404.
I am not sure what the url should look like. I've tried these in Fiddler, all getting the 404. I have googled this quite a bit with no luck.
http://localhost/ershubrest/AppVersions/guid'00000000-e90f-4938-b8f6-000000000000'
http://localhost/ershubrest/AppVersions/'00000000-e90f-4938-b8f6-000000000000'
http://localhost/ershubrest/AppVersions/00000000-e90f-4938-b8f6-000000000000
Here is the code for my controller...
using ERSHubRest.Models;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.OData;
using System.Web.OData.Query;
using System.Web.OData.Routing;
namespace ERSHubRest.controllers
{
[ODataRoutePrefix("AppVersions")]
public class AppVersionsController : ODataController
{
HubModel db = new HubModel();
private bool AppVersionsExists(System.Guid key)
{
return db.AppVersions.Any(p => p.AppVersionId == key);
}
// http GET for select queries
[ODataRoute]
[EnableQuery]
public IQueryable<AppVersions> Get()
{
return db.AppVersions;
}
[ODataRoute("({key})")]
[EnableQuery]
public IHttpActionResult Get([FromODataUri] System.Guid key)
{
IQueryable<AppVersions> result = db.AppVersions.Where(p => p.BusinessId == key);
if (result == null)
{
return NotFound();
}
return Ok(result);
}
// http POST for insert
[ODataRoute()]
[HttpPost]
[EnableQuery(AllowedQueryOptions = AllowedQueryOptions.All)]
public async Task<IHttpActionResult> Post(AppVersions appVersions)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
db.AppVersions.Add(appVersions);
await db.SaveChangesAsync();
return Created(appVersions);
}
// http PUT and PATCH for updates
[ODataRoute()]
[HttpPatch]
[EnableQuery(AllowedQueryOptions = AllowedQueryOptions.All)]
public async Task<IHttpActionResult> Patch([FromODataUri] System.Guid key, Delta<AppVersions> appVersions)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var entity = await db.AppVersions.FindAsync(key);
if (entity == null)
{
return NotFound();
}
appVersions.Patch(entity);
try
{
await db.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!AppVersionsExists(key) )
{
return NotFound();
}
else
{
throw;
}
}
return Updated(entity);
}
[ODataRoute()]
[HttpPut]
[EnableQuery(AllowedQueryOptions = AllowedQueryOptions.All)]
public async Task<IHttpActionResult> Put([FromODataUri] System.Guid key, AppVersions update)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
if ( ! key.Equals( update.BusinessId ))
{
return BadRequest();
}
if (!AppVersionsExists(key))
{
return BadRequest();
}
db.Entry(update).State = EntityState.Modified;
try
{
await db.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if ( ! AppVersionsExists(key))
{
return NotFound();
}
else
{
throw;
}
}
return Updated(update);
}
// last is Delete
[ODataRoute()]
[HttpDelete]
[EnableQuery(AllowedQueryOptions = AllowedQueryOptions.All)]
public async Task<IHttpActionResult> Delete([FromODataUri] System.Guid key)
{
var appVersions = await db.AppVersions.FindAsync(key);
if (appVersions == null)
{
return NotFound();
}
db.AppVersions.Remove(appVersions);
await db.SaveChangesAsync();
return StatusCode(HttpStatusCode.NoContent);
}
// clean up
protected override void Dispose(bool disposing)
{
db.Dispose();
base.Dispose(disposing);
}
}
}
The request URL for PATCH, PUT and DELETE should be:
http://localhost/ershubrest/AppVersions(00000000-e90f-4938-b8f6-000000000000)
OData is using parenthesizes for addressing single entities using keys.
For more URL conventions, the OData V4 URL convention spec can be referred to: http://docs.oasis-open.org/odata/odata/v4.0/os/part2-url-conventions/odata-v4.0-os-part2-url-conventions.html
Try this:
http://localhost/ershubrest/AppVersions(guid'00000000-e90f-4938-b8f6-000000000000')
That should work!!
Odata V1-3 : http://localhost/ershubrest/AppVersions(guid'00000000-e90f-4938-b8f6-000000000000')
Odata V4 : http://localhost/ershubrest/AppVersions(00000000-e90f-4938-b8f6-000000000000)
I've tested Odata for 2 days
I ensure that !