Where clause in oData - c#

Is it possible to use this code in OData?
IQueryable<CallLogInfo> CallLogInfos = _callCenterServiceAccessor.CallLogInfos.Where(x => x.LogId == logid);
var log = CallLogInfos.ToList();
return log.Any();
I checked my request that it generated and I saw this:
http://services/CallCenter/CallCenterDataService.svc/CallLogInfos(1364974501.4)
so get this error:
<m:message xml:lang="en-US">Resource not found for the segment 'CallLogInfo'.</m:message>
but when I manually make a request to this request url:
http://services/CallCenter/CallCenterDataService.svc/CallLogInfos
Its ok.

As far as I know a request like your code should be possible.
Assuming that LogId is the Key column of you OData Service, your code
CallLogInfos.Where(x => x.LogId == logid);
will be transformed internally by the OData Service to
http://services/CallCenter/CallCenterDataService.svc/CallLogInfos(logid)
which is the standard syntax to get an element with a specific Id.
The error message you showed is thrown, if a query for an Id does not find an entry in the list, have you checked if the Id you provide is correct?
(If that is the problem, you can turn off this behavior by setting the IgnoreResourceNotFoundException Property of the service context (see MSDN))
In a test that I made, a query like yours does work, maybe your Odata service implementation contains errors?
You can try your code and your service with a tool like LinqPad which is helpful to try out things like that.

Related

Is Request.Cookies["value"] in c# controller some static reference

I am having difficulty to understand some code from GitHub (I am learning angular, however this is server side code written in c#)
The code is available on GitHub code).
I can't completely understand the very first line of code var refreshToken = Request.Cookies["refreshToken"]; Where does Request.Cookies come from? It is not a variable and it looks like a static call to some array Cookies. How does the element of that array happen to contain "refresh-token" item?
Could someone please explain this? (this code comes from the class derived from BaseController)
[HttpPost("refresh-token")]
public ActionResult<AuthenticateResponse> RefreshToken()
{
var refreshToken = Request.Cookies["refreshToken"];
var response = _accountService.RefreshToken(refreshToken, ipAddress());
setTokenCookie(response.RefreshToken);
return Ok(response);
}
When you work in an HTTP application, .NET manages some context for you. A bunch of stuff you write, like your POST action, is provided with an HTTP context, which has properties that provide information about the request. This includes headers, cookies, etc.
When you use Request within an MVC controller (or some other HTTP context) you'll get access to the HttpContext and Request that relates to the specific single request. It feels like magic, but it's the framework doing the work for you.
A bit more information on context.
You need to check other serverside codes which set the cookie,Cookie is created in serverside firstly and sent to User Agent,often stored in your browser.next time you send a request,your request may contain the cookie
you could check the codes like:Response.Cookies.Append(....)

C# HttpRequestMessage.GetCorrelationId method returns duplicates

My team and I have been working on this issue for a couple of days and we can't determine the root cause why GetCorrelationId() returns duplicates GUID sometimes.
Within the application that I'm working right now we use the correlation id to tie up the request path.
For example the UI sends a Save request to the API in .NET. When the API calls the save method in the query service from the controller, it pass through the result of Request.GetCorrelationId() to the method call.
The save method in the query service uses this parameter to insert a new row in the audit_logs table with the request information.
The save method then calls other save methods on nested objects that belongs to the main Object, passing the correlation_id generated in the controller.
Something like this
[ Controller ]
var correlation_id = HttpRequestMessage.GetCorrelationId();
{
ParentObject.save(correlation_id) -> {
ChildObject1.save(correlation_id),
ChildObject2.save(correlation_id),
}
}
My question is. Is this an issue of how GetCorrelationId creates the GUID object or there is something wrong with the configuration of the framework?
The framework is .NET Framework 4.6.1
We see this issue in IIS Express and IIS server
I can't share code but I'll do my best to share as much information is needed to troubleshoot this issue.
This are some examples of duplicates GUID
Thanks
OK I found a solution. I'm posting it so if someone else has the same issue can get this example.
After some more digging on Google I found this post
https://www.codeproject.com/Articles/392926/Grouping-application-traces-using-ActivityId
Sebastian is using the ActivityId generated by IIS to tied together the different commands executed during his process.
Then I found the source code of HttpRequestMessageExtensions https://github.com/aspnet/AspNetWebStack/blob/master/src/System.Web.Http/HttpRequestMessageExtensions.cs
There, you can see that the method GetCorrelationId() uses the ActivityId to assign a correlation ID to the request.
ActivityId is not completely random. It is tied to the thread started by IIS. I notice that all our request from localhost:port have the same string at the end b63f-84710c7967bb.
We wanted to tied all the commands executed to save an object or retrieve it. So all we needed was a random Guid generated per request. Following the example posted by Sebastian, I stored the current ActivityId in an aux variable, then assigned a new GUID to it, executed Request.GetCorrelationId() and finally assigned back the ID stored in the aux variable to the ActivityId.
In pseudo code =>
Guid prevActivityId = Trace.CorrelationManager.ActivityId
Trace.CorrelationManager.ActivityId = Guid.NewGuid()
...
guid correlation_id = Request.GetCorrelationId()
...
Trace.CorrelationManager.ActivityId = prevActivityId
Hope this is helpful to someone else.

WebApi Internal Server Error

I have 2 projects, a Front-End (AngularJS) and a Back-End (C# Web-Api). The thing is, when the front-end query the api (e.g GET localhost/api/Especialistas?rol=XXXX) I get a 500 error. Here is the code of the API:
public IHttpActionResult GetEspecialista(string rol)
{
Especialista especialista = db.Especialistas.First( e=> e.Rol == rol);
if (especialista == null)
{
return NotFound();
}
return Ok(especialista);
}
The API is working, since I reach the return Ok(especialista).
The Front-end is using this Restangular to query the API
Restangular.one("Especialistas?rol=XXXX").get()
The Network console shows a request 200 OK OPTION, but a 500 Internal Server Error GET.
I tried a message handler in the WebApiConfig.cs file to check if the GET request was reaching the Api, and is indeed reaching it, so I don't know what happened, since I didn't change any configuration file.
Any clue on how to fix this problem will be appreciated, thanks.
If your action is called successfully, but still receive a 500 error, I think the error is created by the serializing of especialista object when converted to a HTTP response.
Most probably, serialization fails because of some navigation properties which creat cycles in your object graph. It is recommended to return simple objects, not entity framework models.
Try the following:
var retObj = new { Prop1 = especialista.Prop1, Prop2 = especialista.Prop2 };
return Ok(retObj);
If above code works, I suggest creating service models "mirror" objects that should be populated based on your data models. These objects should be returned instead of data models.
A good helper to avoid the boilerplate code of property value assignments is Automapper.

ODataClient MaxProtocolVersion V3

I am trying to consume OData from a windows forms. So, what i have done to now is create a new project, i added a web service reference to the OData service and try to consume it.
My code is:
var VistaEntities = new VrExternalEntities("serviceURI");
var query = VistaEntities.VRtblCinemaType
.Where(
x =>
x.VRtblCinema_Operators
.Any
(
z =>
z.VRtblSessions
.Any
(
y =>
y.Session_dtmDate_Time > DateTime.Now
)
)
)
.Select
(
x =>
new
{
x.CinType_strCode,
x.CinType_strDescription
}
);
If i remove the Where clause it works. If i do it says that Any is not supported. I know i have to set MaxProtocolVersion to V3 but i do not know how to do it. I don't have an entity context or anything else. I only have what i have stated above.
Please provide steps on how to accomplish that.
Thanks in advance.
Giannis
You must retrieve the configuration of your DataService and set the MaxProtocolVersion of its behavior to V3.
The best place to do this is certainly in the InitializeService static method you can define in your service class, which will be given the proper configuration object as its config parameter by the environment. It will only be invoked once, typically at the first request.
Note #1: You need WCF Data Services 5.0 or greater. The best way to get it is probably via the Server NuGet package.
Note #2: Oddly enough, the DataServiceProtocolVersion type, although in the Common namespace, is included in the Client assembly (Microsoft.Data.Services.Client, provided by the Client NuGet package). I suggested a better organization here.
public class Vista : DataService<VistaContext>
{
public static void InitializeService(DataServiceConfiguration config)
{
config.SetEntitySetAccessRule(...);
config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V3;
...
}
}
Update:
The client may indeed specify the desired version in the requests by using the DataServiceVersion HTTP header. It's currently recommended that you specify and support a range of versions using the MinDataServiceVersion and MaxDataServiceVersion headers if you can, for obvious reasons. Note however that the MinDataServiceVersion will be removed in OData 4.0 (see appendix E.1 of part 1 and "What's new" documents drafts).
The relevant documentation for the WCF Data Services 5.x implementation is available here. The documentation specific to the client seems pretty scarce, but looking at the reference you can see that you must use this constructor for the DataServiceContext to specify the maximum protocol version, and it looks like you cannot change it at any one point for subsequent requests without rebuilding a new context. You may attempt to fiddle with the headers directly, but I wouldn't expect it to work reliably (or at all).
So, to answer your question, you really need control over how you create the context for the client.

Best practice for getting single record from WCF DataService Client

I have DataService where T is an EntityFramework DbContext class
My client app is a Windows Forms app with a Service Reference.
What is the best approach to get a single entity from the service?
This code works:
var uri = new Uri("http://localhost/ProductService.svc/");
var context = new ProductContext(uri);
var result = context.Products.Where(x => x.ProductId == 123).FirstOrDefault();
However, it works because the product exists. That is because I can see the result by executing
http://localhost/ProductService.svc/Products(123)
in the browser. If I want to query product 123456, which does not exist in the database
http://localhost/ProductService.svc/Products(123456)
I see an errortext ` Resource not found for the segment 'Products'
The thing is, on the client side I get an exception but I would expect FirstOrDefault() to be null instead. Sure I could use some exception handling, but I am wondering if my approach is correct or if there is a better way to fetch a single object.
Update: Found the solution here https://stackoverflow.com/a/5987733/98491
The key is to set
context.IgnoreResourceNotFoundException = true;
Now SingleOrDefault() and FirstOrDefault() behave like I would expect. But I am still wondering if this is the right decision because in a browser
http://localhost/ProductService.svc/Prodducts(1)
(notice the typo) throws the same ResourceNotFound exception

Categories

Resources