LinqPad4 - Can I execute action of odata with parameters in linqpad? - odata

I connected to the service and ran selects.
I saw that I can insert object but I didn't find a way to run action on ODATA.
Here for example an action that I have:
[System.Web.Http.HttpPost]
public void SendAuxiliary([FromODataUri] int key, ODataActionParameters parameters)
{

Related

odataroute same name for post and get

I am having one controller Name MailingAddress and in starup.cs i had used below code to set odataroute .If i am specifying same odataroute for building 2 entitys i am getting run time error .How can we build two entityes with same odata route so that get and post will be called with same name?
builder.EntitySet<BEAccountAddresses>("MailingAddresses");
builder.EntitySet<BEMailingAddressesRequest>("MailingAddresses");
[HttpPost]
[ODataRoute("MailingAddress")]
public BEMailingAddressConfirmation AddMailingAddresses(BEMailingAddressesRequest beMailingAddressesRequest)
[HttpGet]
[EnableQuery]
[ODataRoute("MailingAddresses({key})")]enter `enter code here`code here
public BEAccountAddresses Get([FromODataUri]string key)

Attribute routing is failing for MVC/WebApi combo project

I am trying to create an ASP.NET app that is both MVC and Web Api. The default controller (HomeController) returns a view that is composed of some HTML and jQuery. I would like to use the jQuery to call the API that is part of the same project.
I have the API setup and have been testing it with Postman but I get the following error when trying to reach the endpoints in the API.
{
"Message": "No HTTP resource was found that matches the request URI 'http://localhost:19925/api/encryption/encrypt'.",
"MessageDetail": "No action was found on the controller 'Values' that matches the request."
}
I am attempting to use attribute routing so I am pretty sure that is where I am going wrong.
[RoutePrefix("api/encryption")]
public class ValuesController : ApiController
{
[HttpPost]
[Route("encrypt")]
public IHttpActionResult EncryptText(string plainText, string keyPassPhrase)
{
// Method details here
return Ok(cipherText);
}
}
I have the route prefix set to api/encryption. I also have the method using the route encrypt and marked as a HttpPost. Below is my WebApiConfig which I think is configured properly for attribute routing.
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Web API routes
config.MapHttpAttributeRoutes();
// Default MVC routing
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
By my understanding a POST to the following URL should reach the method ..
http://localhost:19925/api/encryption/encrypt
yet it isn't. I am posting the two string values to the method via Postman. I have attached a screen capture (and yes the keyPassPhrase is fake).
Here is the global.asax as requested ...
public class WebApiApplication : 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);
}
}
One other thing to note ... that when I change from GET to POST in Postman it works .. as long as I am sending the parameters along in the query string. If I send the parameters in the body I get the original error.
The problem was that I was trying to POST two values to an API method that accepted two parameters. This is not possible with the API (well not without some work arounds) as the API method is expecting an object rather than two different primitive types (i.e. String).
This means on the server side I needed to create a simple class that held the values I wanted to pass. For example ...
public class EncryptionPayload
{
public string PlainText { get; set; }
public string PassPhrase { get; set; }
}
I then modified my API method to accept a type of this class
[Route("encrypt")]
[HttpPost]
public IHttpActionResult EncryptText(EncryptionPayload payload)
{
string plainText = payload.PlainText;
string passPhrase = payload.PassPhrase
// Do encryption stuff here
return Ok(cipherText);
}
Then inside that controller I pulled the Strings I needed from the EncryptionPayload class instance. On the client side I needed to send my data as a JSON string like this ..
{"plainText":"this is some plain text","passPhrase":"abcdefghijklmnopqrstuvwxyz"}
After changing these things everything worked in Postman. In the end I wasn't taking into account Model Binding, thinking instead that an API endpoint that accepted POST could accept multiple primitive values.
This post from Rick Strahl helped me figure it out. This page from Microsoft on Parameter Binding also explains it by saying At most one parameter is allowed to read from the message body.
Try the following code. It will work :
[RoutePrefix("api/encryption")]
public class ValuesController : ApiController
{
[Route("encrypt"),HttpPost]
public IHttpActionResult EncryptText(string plainText, string keyPassPhrase)
{
// Method details here
return Ok(cipherText);
}
}
Sorry dear it was really compile time error. I edit my code. Please copy it and paste it in yourcode. Mark as answer If i Helped.

Setting AllowedQueryOptions = AllowedQueryOptions.All for all controllers

I have a Web API project where I want to allow the callers to use all the different query options on all controllers.
Inspired by this thread and this thread I added the following code to my WebApiConfig.Register method:
public static void Register(HttpConfiguration config)
{
//[already working configuration code]
//Allow for $format parameter to OData queries
config.Filters.Add(new EnableQueryAttribute()
{
AllowedQueryOptions = AllowedQueryOptions.All
});
}
The code compiles and runs, but when I try to add the $format parameter to a query, I get the same exception as previously:
Query option 'Format' is not allowed. To allow it, set the 'AllowedQueryOptions' property on EnableQueryAttribute or QueryValidationSettings.
Why doesn't the AllowedQueryOptions setting in WebApiConfig get registered for all controllers?
Did you have both [EnableQuery] attribute and ODataQueryOptions parameter in Controller's method? just use [EnableQuery] attribute, it will apply ODataQueryOption after you return your result and it's allow Format by default.
https://github.com/OData/WebApi/blob/master/OData/src/System.Web.OData/OData/EnableQueryAttribute.cs
if you need ODataQueryOptions parameter, then remove [EnableQuery] attribute, create you own validatasetting, things will work.

AuthorizationCodeWebApp.AuthResult result is NULL randomly! after AJAX call in MVC app

I need an advice. I wrote an MVC app to access Google Gmail API (using Google OAuth 2 Authentication), as explained in Google's Tutorial: https://developers.google.com/api-client-library/dotnet/guide/aaa_oauth#web-applications-aspnet-mvc
The idea is - Index action initializes
private static AuthorizationCodeWebApp.AuthResult result;
after it performs Google OAuth2 authentication. That result object has Credentials.Token property that contains issued AccessToken and RefreshToken. Next, Index action returns a vew (rendered HTML) that has a DIV where I want to load Gmail messages asynchronously. When the page loads, there is a Javascript function that fires on page load even in a browser. Simple. That Javascript function makes an AJAX call to Gmail() action in HomeController. It makes these calls with a 1 minute interval (js timer). Since result object is marked as static it should be available to pass Credentials to Gmail API Service method that is implemented in GmailManager helper class:
return PartialView(GmailManager.GetGmail(result.Credential));
The problem is sometimes the result object is null inside the Gmail() action and the NullReferenceException is thrown
I dont understand why this is happening if the result was initialized in Index action and it is static, so it should be alive by the time the call is made to Gmail() action. It should never be null. If it was constantly null I would understand and try to debug and fix it, but it is random and I cannot understand the logic.
If someone understands what is happening please advice.
Below is my HomeController code:
public class HomeController : Controller
{
private static AuthorizationCodeWebApp.AuthResult result;
public async Task<ActionResult> Index(CancellationToken cancellationToken)
{
result = await new AuthorizationCodeMvcApp(this, new AppFlowMetadata()).AuthorizeAsync(cancellationToken);
if (result.Credential == null)
return new RedirectResult(result.RedirectUri);
if (!string.IsNullOrEmpty(result.Credential.Token.RefreshToken))
SaveRefreshTocken(result.Credential.Token.RefreshToken);
return View();
}
public ActionResult Gmail()
{
result.Credential.Token.RefreshToken = WebConfigurationManager.AppSettings["RefreshToken"];
return PartialView(GmailManager.GetGmail(result.Credential));
}
private static void SaveRefreshTocken(string refreshToken)
{
Configuration config = WebConfigurationManager.OpenWebConfiguration("~");
config.AppSettings.Settings["RefreshToken"].Value = refreshToken;
config.Save();
}
}

OData routing for function with 2 parameters

Im creating OData controller and want it to support function with 2 params.
Here is my current code.
OData cofig:
ODataModelBuilder builder = new ODataConventionModelBuilder();
builder.Namespace = "hop";
builder.EntitySet<ScheduleDTO>("Schedules");
var function = builder.Function("GetByEntityAndJurisdiction");
function.Parameter<Guid>("EntityId");
function.Parameter<Guid>("JurisdictionId");
function.ReturnsCollectionFromEntitySet<ScheduleDTO>("Schedules");
Controller:
[ODataRoutePrefix("Schedules")]
public class ScheduleODataController : BaseODataManager, IScheduleODataManager
{
[ODataRoute]
public async Task<IHttpActionResult> GetAsync(ODataQueryOptions<ScheduleDTO> options)
{
.....
return Ok(schedules.Select(x => Mapper.Map<ScheduleDTO>(x)));
}
[HttpGet]
[ODataRoute("GetByEntityAndJurisdiction(EntityId={entityId}, JurisdictionId={jurisdictionId})")]
public async Task<IHttpActionResult> GetByEntityAndJurisdiction(ODataQueryOptions<ScheduleDTO> options, [FromODataUri] Guid entityId, [FromODataUri] Guid jurisdictionId)
{
.....
return Ok(schedules.Select(x => Mapper.Map<ScheduleDTO>(x)));
}
}
Starting my app, I have following error:
A first chance exception of type 'System.InvalidOperationException' occurred in System.Web.OData.dll
Additional information: The path template 'Schedules/GetByEntityAndJurisdiction(EntityId={entityId}, JurisdictionId={jurisdictionId})' on the action 'GetByEntityAndJurisdiction' in controller 'ScheduleOData' is not a valid OData path template. The request URI is not valid. Since the segment 'Schedules' refers to a collection, this must be the last segment in the request URI or it must be followed by an function or action that can be bound to it otherwise all intermediate segments must refer to a single resource.
How to resolve this problem? Thanks in advance.
#Vladimir
In your controller, you add a prefix attribute [ODataRoutePrefix("Schedules")] on the controller. Doing so will add the prefix string at head of all the [ODataRoute] in the same controller. So, for below action
public async Task<IHttpActionResult> GetByEntityAndJurisdiction(ODataQueryOptions<ScheduleDTO> options, [FromODataUri] Guid entityId, [FromODataUri] Guid jurisdictionId)
{...}
the full Uri template should be:
Schedules/GetByEntityAndJurisdiction(EntityId={entityId}, JurisdictionId={jurisdictionId})
Obviously, This Uri is invalid because:
The collection of Schedules doesn't have a bound function named GetByEntityAndJurisdiction
Even though GetByEntityAndJurisdiction is a bound function, you should call the bound function through it's namespace-qualified function name.
Maybe, It's confused that you have build the function as the following codes:
var function = builder.Function("GetByEntityAndJurisdiction");
However, it means to build an unbound function. An unbound function is called through function import by issuing a GET request to a URL identifying the function import and passing parameter values using inline parameter syntax. The canonical URL for a function import is the service root, followed by the name of the function import.
So, you can change your codes as follows to make it work:
If you want to keep the model schema unchanged, that is to build GetByEntityAndJurisdiction as unbound function, please remove the ODataRoutePrefix("Schedules")] from your controller. Or create a new controller (any controller), move the action into the new controller but don't add the Prefix attribute.
If you want to change the schema and keep the controller unchanged, that is to GetByEntityAndJurisdiction as bound function.
Please do as follows :
var entity = builder.EntitySet<ScheduleDTO>("Schedules").EntityType;
var function = entity.Collection.Function("GetByEntityAndJurisdiction");
...
For more information about function, you can refer to OData.Org or Function Sample page, or Function blog.

Resources