Linq expression fails in query parser under bizarre conditions - c#

I've been unable to figure this error out for some time now and am hoping that someone can provide some insight. First, I'll explain the conditions and next I'll describe the conditions under which the error does/doesn't occur.
I have a web api, it has two endpoints /api/getData1 and /api/getData2
I have a web client that makes requests to /api/getData1
I have another application that makes requests to api/getData2
The web api controllers for getData1 and getData2 both end up making a service call to dataService.getData(DateTime date)
dataService.getData(DateTime date) calls StaticFilterClass.buildFilter(DateTime date)
StaticFilterClass.buildFilter(DateTime date)
AlarmFilter filter = null;
var paramExpr = Expression.Parameter(typeof(Alarm), "a");
var fieldRef = Expression.Property(paramExpr, "UtcEnd");
var binaryExpression = Expression.And(
Expression.GreaterThanOrEqual(fieldRef, Expression.Constant(earliestEnd.Date.Add(new TimeSpan(0, 0, 0)).ToUniversalTime(), typeof(DateTime))),
Expression.LessThanOrEqual(fieldRef, Expression.Constant(latestEnd.Date.Add(new TimeSpan(23, 59, 59)).ToUniversalTime(), typeof(DateTime))));
filter = (AlarmFilter)Expression.Lambda(binaryExpression, paramExpr);
dataService.getData(DateTime date), after getting the filter
dbAlarms = tenantDb.Alarms.Where(completeFilter)?.ToList() ?? dbAlarms;
The line above conditionally throws
"The query view generated for the EntitySet 'Alarms' is not valid. The query parser threw the following error : The argument type 'Edm.String' is not compatible with the property 'UtcEnd' of formal type 'Edm.DateTime'. Near member access expression, line 3, column 77.."}
Now, the conditions under which this line throws an error is what has me puzzled.
When the web api is started, if my web client goes to /api/getData1, there is no error. Subsequent calls from the web client to /api/getData1 succeed and subsequent calls from the other application to /api/getData2 succeed.
When the web api is started, if my other application goes to /api/getData2 first, the error above is generated. Subsequent calls from the application to /api/getData2 and subsequent calls from the web client to /api/getData1 throw the error above.
Can anyone help to point me in the right direction?
Edit:
It seemed to have something to do with the load order of the database project .dll (referenced by the client app and the api). I moved a couple of db transactions from the client application (where it accessed the db directly) into the web api so that the api would be the first thing to hit the database, and because it made more sense anyway. Still not sure of the root cause, but this resolves the issue.

I can think only 2 think:
1) You need to specify a where return object like below:
bAlarms = tenantDb.Alarms.Where<MyReturnObject>(completeFilter)?.ToList<MyReturnObject>() ?? dbAlarms;
2) Inside "alarms" there is a static class/function that will be accessed at the same time by getData1 and Getdata2.

Related

Show more than 5000 records from CRM in C#

I am trying to understand how FetchXml works (or any other method) because I want to retrieve and process more than the limit of 5000 records that CRM returns on the api call below.
My base url looks like this: http://crm.domain.com:1234/api/data/v8.0/
the resource is: emails
and query options are: $top=50000&$filter=description ne null and not contains(sender, '#not-interesting.com')
I'm trying to copy the code from
https://learn.microsoft.com/en-us/previous-versions/dynamicscrm-2016/developers-guide/gg327917(v=crm.8)?redirectedfrom=MSDN
but I'm having issues with creating the OrganizationServiceProxy object like this:
var creds = new ClientCredentials();
creds.UserName.UserName = CrmApiUsername;
creds.UserName.Password = CrmApiPassword;
using (var _serviceProxy = new OrganizationServiceProxy(
new Uri(CrmApiBaseAddress), null, creds, null))
{
// This statement is required to enable early-bound type support.
_serviceProxy.EnableProxyTypes(); // ...
I'm getting an error:
Metadata contains a reference that cannot be resolved: 'http://crm.domain.com:1234/data/v8.0/?wsdl&sdkversion=90'.'
WebException: The remote server returned an error: (404) Not Found.
You mixed up these two:
Web API - which was available after v8.0
2011 endpoint - which is deprecated now but was available for really long time
Read more
When you use web api the url will be like: https://yourcrm.crm#.dynamics.com/api/data/v8.0/
In case of Organization Service Proxy still the 2011 endpoint: https://yourcrm.crm.dynamics.com/XRMServices/2011/Organization.svc
For breaking the 5000 records limitation & getting more than 5k records, the pagination concept has to be used. How to fetch more than 5000 entities from CRM
For more ideas, I have answered in this SO thread about other options.

Azure .NET SDK not handling filters correctly (ConsumptionClient)?

I'm calling the Azure Usage API trying to use a filter to get machine specific information.
The return values are valid, but it seems like either the REST API or the C# library is sending the request incorrectly.
This is the code:
var filterString = $"instanceName eq '{vm.VirtualMachineName}'";
vmConsumptionData = await consumptionClient.Item1.UsageDetails.ListAsync(
scope: $"/subscriptions/{subscriptionId}",
filter: filterString
);
According to the log, my request is being sent with the following:
https://management.azure.com//subscriptions/{SubscriptionId}/providers/Microsoft.Consumption/usageDetails?$filter=instanceName%20eq%20%27{correct instance name}%27&api-version=2017-11-30
However, this is always returning the same 24 results, even when submitting a different instance name.
I have tried removing certain parts of the filter 'query' and it always returns the same 24 results (which are not virtual machine resource types).
Am I calling the library incorrectly? Reference here
Apparently the SDK differs in the filtering and is somewhat clear from the documentation. You should call with the following:
properties/usageEnd (Utc time)
properties/usageStart (Utc time)
properties/resourceGroup
properties/instanceName
properties/instanceId
Changing my filterString to:
var filterString = $"properties/instanceName eq \'{vm.VirtualMachineName}\'";
Did the job.

ASP.NET WebAPI 2.2 SPA with social login and no MVC dependencies

I have been designing an application which is just a statically served client page designed to use bearer tokens to authenticate with the backing API, however recently I have been trying to add social login options to the back-end but have found it very difficult to find any examples not using MVC dependencies which I would like to avoid if possible.
This question was a great help to get started: ASP.NET Web API social authentication for Web and Mobile
However I have been struggling to get my project to work in the same manor, basically in the question I referenced he has configured a OAuthAuthorizationServerOptions.AuthorizeEndpointPath like this:
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/token"),
Provider = new ApplicationOAuthProvider(PublicClientId),
AuthorizeEndpointPath = new PathString("/api/account/externallogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
//AllowInsecureHttp = false
};
Also in his backing api account controller he has the following action:
[OverrideAuthentication]
[HostAuthentication(DefaultAuthenticationTypes.ExternalCookie)]
[AllowAnonymous]
[Route("ExternalLogin", Name = "ExternalLogin")]
public async Task<IHttpActionResult> GetExternalLogin(string provider, string error = null)
In this example I have not been able to figure out what the first parameter of the RouteAttribute (template) is actually referencing in the project, if anything, could someone maybe explain what it is doing in this context?
Now when running the sample project provided in the question sending a GET request to 'api/Account/ExternalLogin' the request will be handled on the action in his API account controller and I assume it has something to do with OverrideAuthentication but am getting a little out of my depth here and struggling to find strong examples of other usages of this attribute.
However I am fairly certain I have configured my WebAPI project correctly in the way he has described, however when sending a GET request to my OAuthAuthorizationServerOptions.AuthorizeEndpointPath it is not handled on my API account controller but instead by my implementation of OAuthAuthorizationServerProvider which returns a 'invalid_request' error.
Can anyone think of something that I might be overlooking which is causing my API account controller action to be ignored?
I also had a read through this article but it seems to have been written in an older version of WebAPI:
https://thompsonhomero.wordpress.com/2015/01/21/creating-a-clean-web-api-2-project-with-external-authentication-part-2/
Thanks for any help,
Alex.
Without actually seeing your GET requests that are being made, I can only assume that they do not meet expectations by the OAuth provider.
The provider first validates the request being made, THEN it hands control over to the endpoint's controller. Your code is most likely correct, it's just that the request is malformed.
I made a new project and was able to replicate the issue you describe by making a get request to the AuthorizeEndpointPath. Unfortunately, there's not much to go off of as to why, however if you decompile source, or manage to find the source, you can see what's going on here.
Decompiling the calling code of ApplicationOAuthProvider.ValidateClientRedirectUri I get:
await this.Options.Provider.ValidateClientRedirectUri(clientContext);
if (!clientContext.IsValidated)
{
LoggerExtensions.WriteVerbose(this._logger, "Unable to validate client information");
flag = await this.SendErrorRedirectAsync(clientContext, (BaseValidatingContext<OAuthAuthorizationServerOptions>) clientContext);
}
else
{
OAuthValidateAuthorizeRequestContext validatingContext = new OAuthValidateAuthorizeRequestContext(this.Context, this.Options, authorizeRequest, clientContext);
if (string.IsNullOrEmpty(authorizeRequest.ResponseType))
{
LoggerExtensions.WriteVerbose(this._logger, "Authorize endpoint request missing required response_type parameter");
validatingContext.SetError("invalid_request");
}
else if (!authorizeRequest.IsAuthorizationCodeGrantType && !authorizeRequest.IsImplicitGrantType)
{
LoggerExtensions.WriteVerbose(this._logger, "Authorize endpoint request contains unsupported response_type parameter");
validatingContext.SetError("unsupported_response_type");
}
else
await this.Options.Provider.ValidateAuthorizeRequest(validatingContext);
if (!validatingContext.IsValidated)
{
flag = await this.SendErrorRedirectAsync(clientContext, (BaseValidatingContext<OAuthAuthorizationServerOptions>) validatingContext);
}
else
{
this._clientContext = clientContext;
this._authorizeEndpointRequest = authorizeRequest;
OAuthAuthorizeEndpointContext authorizeEndpointContext = new OAuthAuthorizeEndpointContext(this.Context, this.Options, authorizeRequest);
await this.Options.Provider.AuthorizeEndpoint(authorizeEndpointContext);
flag = authorizeEndpointContext.IsRequestCompleted;
}
}
In this code, you can see that if the request has been validated and the request's specified ResponseType is not provided, it set's the context's error to "invalid_request".
I was able to get the request to go through to the ExternalLogin controller method successfully using the following request URI:
http://localhost:18086/api/Account/ExternalLogin?provider=none&client_id=self&redirect_uri=http://localhost:18086/&response_type=token`
P.S. As far as the route attribute on the controller, the "template" field specifies the string that will be used as a template to match incoming request URIs against to determine where the request should be routed.
P.P.S. Actual source code for the decompiled snippet can be found here

Azure Mobile Services PullAsync() Not Filling Sync Table

So I have a remote table called Profile that has multiple entries made already. Now I'm trying to integrate offline capabilities into my application. As of right now I'm having issues with PushAsync and PullAsync methods in my code.
I would like to be able to copy all the data from my remote table into my local table just by calling PullAsync, and although it doesn't throw any exceptions it also doesn't populate my table. Here's an example of what I mean.
var db = new SQLiteConnection("syncstoreTEMP.db");
var store = new MobileServiceSQLiteStore("syncstoreTEMP.db");
store.DefineTable<Profile>();
MobileService.SyncContext.InitializeAsync(store).Wait();
var remoteValues = MobileService.GetTable<Profile>()
.ToListAsync()
.Result;
MobileService.GetSyncTable<Profile>()
.PullAsync(null, MobileService.GetSyncTable<Profile>().CreateQuery())
.Wait();
var localValues = MobileService.GetSyncTable<Profile>()
.ToListAsync()
.Result;
When I run this code remoteValues has a total length of 5, but localValues still shows 0 entries even after issuing a Pull from remote. How can I get the sync table to match my remote table?
It's strange that you're not getting any exceptions, but you seem to be creating two connections to your local store. You should not have the line for new SQLiteConnection, only the line that creates the MobileServiceSQLiteStore.
Here's a tutorial that walks through how to set things up: https://azure.microsoft.com/en-us/documentation/articles/mobile-services-xamarin-ios-get-started-offline-data/
I also recommend that you add a DelegatingHandler to your MobileServiceClient in order to log all of the requests and responses. Then you can see exactly what's going wrong. Here's a sample that shows this, and also includes a logging extension to the SQLite store so you can see exactly what is happening locally: https://github.com/paulbatum/FieldEngineerLite/blob/master/FieldEngineerLite.Client/FieldEngineerLite/Helpers/LoggingHelpers.cs

C# MVC4 windows username and cookie issues

First, I'm sad to say I'm not sure whether this code should be in the _Layout.cshtml or somewhere in the controller. It needs to run on all pages, so I've put it in the _Layout.cshtml page.
This is for an intranet web app. What I'm attempting to do is this: if a cookie (holding the user's userid) is not found, get the windows username, run it through a class that will go into the database and get the corresponding user's username, and - if we get a user id back - make a cookie containing it. Doesn't sound too hard, but one line in particular, and various incarnations of it, is refusing to be supportive. Here's the code as a whole.
if(!Context.Response.Cookies.AllKeys.Contains("userid")){
var winuser = System.Web.HttpContext.Current.User.Identity.Name;
var winuserid = myprojectname.Models.MyIntranetDataContext.getUserId(winuser).UserID();
if (winuserid == null) {
Response.Redirect("/someotherpage");
} else {
HttpCookie cookieuser = new HttpCookie("userid");
DateTime now = DateTime.Now;
cookieuser.Value = winuserid;
cookieuser.Expires = now.AddMonths(1);
Response.Cookies.Add(cookieuser);
}
}
Line 2 - var winuser... - appears to be the problem. In this current incarnation, I'm getting a build error: An object reference is required for the non-static field, method, or property 'myprojectname.Models.MyIntranetDataContext.getUserId(string)'
It doesn't like it when I add a .ToString to it either.
I've tried making winuser this as well:
Page.User.Identity.Name;
That gave no build errors. When I attempt to Start Debugging, she blows up with this beauty of an error: 'Cannot perform runtime binding on a null reference'
Once I get the windows username, all will be well.
Really, this isn't about cookies, or even mvc to much of an extent (except maybe guidance on where to put this code - the _Layout.cshtml?). Really it's about getting the windows username, which I seem unable to do. Thanks in advance for any assistance you are able to provide.
Note, the above names aren't actual - just for example only.
If they are on the domain, couldn't you use something like the following to retrieve that information?
AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);
WindowsPrincipal principal = (WindowsPrincipal)Thread.CurrentPrincipal;
WindowsIdentity identity = (WindowsIdentity)principal.Identity;
String userName= principal.Identity.Name;

Categories