I'm building an OData 3 service on Web API 2.2.
The service is correctly returning the metadata for my entities, but returns 406 Not Available when I query one of the actual entities. I've done quite a bit of research (I'm currently following several tutorials), but I haven't found anything that actually works.
Here's my WebApiConfig:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;
using System.Web.OData.Builder;
using System.Web.OData.Extensions;
namespace MyProject
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
ODataModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<MarvelCharacter>("MarvelCharacters");
config.MapODataServiceRoute(
routeName: "Marvel",
routePrefix: "dude",
model: builder.GetEdmModel());
}
}
}
And my controller (not complete, but you get the idea):
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using System.Web.Http.OData;
using System.Web.Http.OData.Query;
using Microsoft.Data.OData;
using MyProject;
namespace MyProject.Controllers
{
public class MarvelCharactersController : ODataController
{
private static ODataValidationSettings _validationSettings = new ODataValidationSettings();
// GET: odata/MarvelCharacters
public IHttpActionResult GetMarvelCharacters(ODataQueryOptions<MarvelCharacter> queryOptions)
{
// validate the query.
try
{
queryOptions.Validate(_validationSettings);
}
catch (ODataException ex)
{
return BadRequest(ex.Message);
}
var entities = new myEntities();
var marvelCharacters = (from c in entities.MarvelCharacters select c).ToList();
return Ok<IEnumerable<MarvelCharacter>>(marvelCharacters);
}
}
}
Turns out the answer to this one was pretty simple, but not covered well by any documentation I could find.
I was trying to implement an OData 3 endpoint on WebAPI 2.2. I was following several different tutorials, some for OData 3 and some for OData 4.
I was using OData 4 (System.Web.OData) in my WebApiConfig and OData 3 (System.Web.Http.OData) in my controller. Turns out, they don't play well together.
I decided to post the answer here in case anyone else has a similar issue.
To add a little value, and since I was mixing both anyway, I decided to go ahead and setup support for both version 3 and 4 by aliasing the namespaces in my WebApiConfig and then creating versioned controllers.
WebApiConfig:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;
using ODataV3 = System.Web.Http.OData;
using ODataV4 = System.Web.OData;
namespace MyProject
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// OData V3 Route
ODataV3.Builder.ODataModelBuilder builder3 = new ODataV3.Builder.ODataConventionModelBuilder();
builder3.EntitySet<MarvelCharacter>("MarvelCharactersV3");
// The MapODataRoute function is deprecated in WebAPI 2.2,
// but I haven't found an alternative for supporting OData 3.
config.Routes.MapODataRoute(
routeName: "Marvel3",
routePrefix: "dude3",
model: builder3.GetEdmModel());
// ODate V4 Route
ODataV4.Builder.ODataModelBuilder builder4 = new ODataV4.Builder.ODataConventionModelBuilder();
builder4.EntitySet<MarvelCharacter>("MarvelCharactersV4");
ODataV4.Extensions.HttpConfigurationExtensions.MapODataServiceRoute(
configuration: config,
routeName: "Marvel4",
routePrefix: "dude4",
model: builder4.GetEdmModel());
}
}
}
MarvelCharactersV3 (OData 3):
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using System.Web.Http.OData; // OData V3
using System.Web.Http.OData.Query;
using Microsoft.Data.OData;
using MyProject;
namespace MyProject.Controllers
{
public class MarvelCharactersV3Controller : ODataController
{
private static ODataValidationSettings _validationSettings = new ODataValidationSettings();
// GET: odata/MarvelCharacters
public IHttpActionResult GetMarvelCharactersV3(ODataQueryOptions<MarvelCharacter> queryOptions)
{
// validate the query.
try
{
queryOptions.Validate(_validationSettings);
}
catch (ODataException ex)
{
return BadRequest(ex.Message);
}
var entities = new myEntities();
var marvelCharacters = (from c in entities.MarvelCharacters select c).ToList();
return Ok<IEnumerable<MarvelCharacter>>(marvelCharacters);
}
}
}
MarvelCharactersV4 (OData 4):
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using System.Web.OData; // OData 4
using System.Web.OData.Query;
using Microsoft.Data.OData;
using MyProject;
namespace MyProject.Controllers
{
public class MarvelCharactersV4Controller : ODataController
{
private static ODataValidationSettings _validationSettings = new ODataValidationSettings();
// GET: odata/MarvelCharacters
public IHttpActionResult GetMarvelCharactersV4(ODataQueryOptions<MarvelCharacter> queryOptions)
{
// validate the query.
try
{
queryOptions.Validate(_validationSettings);
}
catch (ODataException ex)
{
return BadRequest(ex.Message);
}
var entities = new myEntities();
var marvelCharacters = (from c in entities.MarvelCharacters select c).ToList();
return Ok<IEnumerable<MarvelCharacter>>(marvelCharacters);
}
}
}
It's probably not the best architecture (I will probably create a library to consolidate similar code between the controllers), but I've tested and I can successfully query via OData 3 and OData 4, so I'm happy enough with it for now.
Related
Trying to follow an asp.net tutorial. How how to import DBModel() class or what am I doing wrong?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using WebApplication2.Models;
namespace WebApplication2.Controllers
{
public class CollegeController : Controller
{
// GET: College
public ActionResult Index()
{
return View();
}
public ActionResult GetData()
{
using (DBModel db = new DBModel())
{
}
}
}
}
If you are using Visual Studio or JetBrains Rider:
You need to add the directive to the namespace or assembly reference.
Try putting the cursor above the DBModel word and use key combination: ALT + Enter.
You should see something similar to the image below:
Most of the time you'll only see one suggestion. Click on it.
I cannot figure out why code below is not working. It is causing a build error:
IQueryable<InventoryTbl>' does not contain a definition for 'FirstOrDefault' and the best extension method overload 'Queryable.FirstOrDefault<AdminModel>(IQueryable<Admin>)
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Data.Entity;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using RuciyanaSweets.Models;
[HttpGet]
public ActionResult AdminAddorEdit(int id = 0)
{
if (id==0)
return View(new Model());
else
{
using (Entities db = new Entities ())
{
return View(db.TableName.Where(x => x.FieldID == id).FirstOrDefault< Model >());
}
}
}
The definition TSource FirstOrDefault<TSource>(this IQueryable<TSource> source) is part of System.Linq namespace. Check that your project referencing to System.Core and you have using System.Linq; and using System.Data.Entity;.
Be sure you installed the EntityFramework package.
Queryable.FirstOrDefault Method
I'm having a hard time getting the Output for a Webhook on a specific part of JSON Request.
You can see it right here:
I'm using Ngrok for getting the requests. I also created a class which I will call for parsing or getting the JSON file but it failed:
public class FormData
{
public string Data { get; set; }
}
This is the endpoint being posted to:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json.Linq;
using MultipartParser;
using MultipartParser.Data;
using WebApplication3.Objects;
using Newtonsoft.Json;
namespace WebApplication3.Controllers
{
[Route("api/[controller]")]
public class ValuesController : Controller
{
// POST api/values
[HttpPost]
public string Post(string mode, string challenge, FormData data)
{
string test = data.Data;
//JToken jtoken = JSONData.GetValue("active");
//string val = jtoken.ToString();
Console.WriteLine(test);
return test;
}
}
}
Any help will be appreciated.
Your FormData class is wrong which results Null when request received in your api.
Paste your json in below link which will give you the proper class you have to use.
http://json2csharp.com
I have taken code from this page. Basically, i am trying to require SSL on all requests. Here is the code I have:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Net;
using System.Web.Mvc;
using System.Net.Http;
using System.Web.Http.Controllers;
namespace Test
{
public class RequireSSL : ActionFilterAttribute
{
public override void OnAuthorization(HttpActionContext actionContext)
{
if (actionContext.Request.RequestUri.Scheme != Uri.UriSchemeHttps)
{
actionContext.Response = new HttpResponseMessage(System.Net.HttpStatusCode.Forbidden)
{
ReasonPhrase = "HTTPS Required"
};
}
else
{
base.OnAuthorization(actionContext);
}
}
}
}
The problem I am facing is I have a blue scriggily line under OnAuthorization that says "No suitable method to override". Not sure how to fix this. Any ideas?
There is an attribute RequireHttpsAttrobute you can use: RequireHttpsAttribute
If you look carefully at the example, it's deriving from AuthorizationFilterAttribute, not ActionFilterAttribute. If you change that in your example, then it compiles correctly.
A bit rusty here with regards to WCF Services.
I have a custom class named cSecurity.cs which does some custom functions.
I want to use this custom class inside my Service:
This is the App.svc.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
namespace AppServices
{
public class App : IApp
{
public cSecurity _csec;
public string GetItems(int agentID, string agentName)
{
// Need to use some functions from the cSecurity class here???
return _csec.getItems();
}
}
}
This is the cSecurity.cs class:
using System.Collections;
using System.Configuration;
using System.Net;
namespace AppServices
{
public class cSecurity
{
// Some functions defined here....
public string getItems(){
return string.Empty;
}
}
}
But I am getting an error on the line:
public cSecurity _csec;
"The type or namespace name 'cSecurity' could not be found."
This seems pretty trivial but I seem to be lost here.
Appreciate any insight. Thanks.
For some reason, the solution for this was for me to close and restart VS. Not sure what caused the class for it to be not referenced by VS.