I am trying to consume the new Dynamics AX OData endpoint from a .Net console applications, I can see that the authentication is going fine but whenever I try to get the results on my application it ends with an Unauthorized error.
Any idea on what could be the cause or hos to get a more detailed information (logs)?
This is the code that throws the error at line:
foreach (var legalEntity in context.Teams.AsEnumerable())
static void Main(string[] args)
{
Uri oDataUri = new Uri(ODataEntityPath, UriKind.Absolute);
var context = new Resources(oDataUri);
context.SendingRequest2 += new EventHandler<SendingRequest2EventArgs>(delegate (object sender, SendingRequest2EventArgs e)
{
var authenticationHeader = OAuthHelper.GetAuthenticationHeader();
e.RequestMessage.SetHeader(OAuthHelper.OAuthHeader, authenticationHeader);
});
foreach (var legalEntity in context.Teams.AsEnumerable())
{
Console.WriteLine("Name: {0}", legalEntity.Name);
}
Console.ReadLine();
Exception
at Microsoft.OData.Client.QueryResult.ExecuteQuery()
at Microsoft.OData.Client.DataServiceRequest.Execute[TElement](DataServiceContext context, QueryComponents queryComponents)
Unauthorized
at Microsoft.OData.Client.DataServiceRequest.Execute[TElement](DataServiceContext context, QueryComponents queryComponents)
at Microsoft.OData.Client.DataServiceQuery`1.Execute()
at Microsoft.OData.Client.DataServiceQuery`1.GetEnumerator()
at ODataConsoleApplication.Program.Main(String[] args)
Auth logs
Activated Event Time Duration Thread
06/04/2016 9:55:13: 42dbc15a-e068-4f46-9e99-3e41b1820eb9 - AcquireTokenHandlerBase: === Token Acquisition finished successfully.
An access token was retuned:
Access Token Hash: UsxaQ/QZQ+opGz/PC55O5cWYBV8kh1uhvf/CG269WSc=
Refresh Token Hash: 8aKSzBXtBrxr+uVaqhnT/IEg1+gXOkDqq/WHp8SmaBk=
Expiration Time: 06/04/2016 10:55:12 +00:00
User Hash: f1MLHm5K8HDY7tRpkz4amU2+CVFL53JJq3Ybc5q53g0= 4.59s
Activated Event Time Duration Thread
Exception thrown: 'Microsoft.OData.Client.DataServiceQueryException' in Microsoft.OData.Client.dll
("An error occurred while processing this request.") 5.13s [18036] <No Name>
You must add your application in Dynamics in order for it to work.
See System administration > Setup > Azure Active Directory applications
Related
I've implemented the HomeGraph API with the help of the package Google.Apis.HomeGraphService.v1 (1.50.0.2260)
It seems to work fine as well, the ReportStateAndNotification function works fine on the query, execute, and some sync requests.
But when I add a new device to my system through our app and a SYNC request is sent to Google and comes in our backend, the HomeGraph API will return an exception when sending this sync request..
-> The sync request does not throw an exception when I modify a device name in our app. It only occurs when new devices are added.
I've searched through google and multiple StackOverflow posts.. But I'm probably missing something. Most posts say check the API key etc but then the ReportStateAndNotification function should always fail, not only when the sync request comes from Google to our backend.
Could anyone point me in the right direction?
Function that is used for sync requests:
public static void Send(Dictionary<string, object> deviceStateList, string requestId, string googleCustomerId)
{
string deviceIdList = String.Format("({0})", string.Join(", ", deviceStateList.Keys));
try
{
var jsonFilePath = _appSettingsRetriever.PrivateGoogleAuthenticationFile;
string scope = "https://www.googleapis.com/auth/homegraph";
using (var stream = new FileStream(jsonFilePath, FileMode.Open, FileAccess.Read))
{
GoogleCredential credentials = GoogleCredential.FromStream(stream);
if (credentials.IsCreateScopedRequired)
credentials = credentials.CreateScoped(scope);
HomeGraphServiceService service = new HomeGraphServiceService(new BaseClientService.Initializer()
{
HttpClientInitializer = credentials
});
var request = new ReportStateAndNotificationRequest
{
AgentUserId = googleCustomerId,
RequestId = requestId,
Payload = new StateAndNotificationPayload
{
Devices = new ReportStateAndNotificationDevice
{
States = deviceStateList
}
}
};
_log.Debug($"Sending to HomeGraph for devices: {deviceIdList} customer: {googleCustomerId} requestId: {requestId}");
DevicesResource.ReportStateAndNotificationRequest rp = service.Devices.ReportStateAndNotification(request);
ReportStateAndNotificationResponse resop = rp.Execute();
}
}
catch (Exception ex)
{
_log.Error($"Exception in ReportToHomeGraph for Customer: {googleCustomerId}. DeviceList: {deviceIdList}. JsonPath: {_appSettingsRetriever.PrivateGoogleAuthenticationFile} Exception: {ex}.");
}
}
Exception:
2021-09-24 14:16:13,547 [110] ERROR ReportToHomeGraph
Exception in ReportToHomeGraph for Customer: 05. DeviceList: (
fe965e6a-21ad-425f-b594-914bf63510a9,
1cc0ee97-a87f-44c5-a3e3-a39d159ee193,
618cdf94-2b31-434f-b91e-00837d155d4a
).
JsonPath: C:/myfile.json Exception: The service homegraph has thrown an exception:
Google.GoogleApiException: Google.Apis.Requests.RequestError
Requested entity was not found. [404]
Errors [
Message[Requested entity was not found.] Location[ - ] Reason[notFound] Domain[global]
]
at Google.Apis.Requests.ClientServiceRequest`1.<ParseResponse>d__35.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at Google.Apis.Requests.ClientServiceRequest`1.Execute()
at BusinessLogic.GoogleAssistant.TokenService.HomeGraph.ReportToHomeGraph.Send(Dictionary`2 deviceStateList,
String requestId, String googleCustomerId) in C:\Repos\GoogleAssistant
.TokenService\HomeGraph\ReportToHomeGraph.cs:line 57.
When users add a new device, the first step you need to do is to issue a Request Sync to Google. This indicates the set of devices for that user has changed, and you need a new Sync request to update the data in homegraph. Google will follow this by delivering a Sync intent to your fulfillment endpoint, which you can respond with the updated set of devices.
Getting a 404 when calling Request Sync might indicate your Service Account Key might be invalid, or the agent user id you target might be wrong. Otherwise getting an error for your Sync Response might indicate it’s structured incorrectly. You can find out more about how to structure it in our examples.
I am using AzureAd along with the Microsoft Graph Client to do calculations on Excel spreadsheets. It works most of the time but every now and again the request comes back with a Invalid Session error:
Status Code: BadRequest
Microsoft.Graph.ServiceException: Code: InvalidSession
Message: The target session is invalid.
Inner error:
Code: invalidSessionReCreatable
Message: The session specified in the request does not exist or is invalid due to a transient error.
Inner error:
Code: InvalidOrTimedOutSession
Message: We noticed that you haven't been interacting with this workbook, so we paused your session.
It seems like the session gets paused before the API gets to finish the call (which happens in less than a second).
Startup Code to configure AD and Graph Services:
services.AddMicrosoftIdentityWebApiAuthentication(Configuration, "AzureAd")
.EnableTokenAcquisitionToCallDownstreamApi()
.AddMicrosoftGraph(Configuration.GetSection("GraphBeta"))
.AddInMemoryTokenCaches();
Creating the session:
WorkbookSessionInfo res = await _graphServiceClient.Groups[_groupId].Drive.Items[productStructureCalculator.CalculatorId].Workbook
.CreateSession(persistChanges)
.Request()
.Header("Prefer", "respond-async")
.PostAsync();
Doing a batch request:
var batchRequestInfo = CreateBatchRequestAsync(sessionId, structure, productStructureCalculator, productMatrixInputs);
var resultRequest = _graphServiceClient.Groups[_groupId].Drive.Items[productStructureCalculator.CalculatorId].Workbook.Worksheets[productStructureCalculator.SheetName]
.Range("D6:J6")
.Request()
.Header("workbook-session-id", "{" + sessionId + "}")
.Header("Prefer", "return=minimal")
.GetHttpRequestMessage();
resultRequest.Method = HttpMethod.Get;
var resultRequestID = Guid.NewGuid().ToString();
var batchResultRequestStep = new BatchRequestStep(
resultRequestID,
resultRequest,
new List<string> { batchRequestInfo.LastEventRequestId }
);
batchRequestInfo.BatchRequestContent.AddBatchRequestStep(batchResultRequestStep);
var returnedResponse = await _graphServiceClient.Batch.Request().PostAsync(batchRequestInfo.BatchRequestContent);
As per | Microsoft Docs ,
InvalidSessionReCreatable :The session specified in the request does not exist or is invalid due to a transient error.
Error Handling : The Microsoft Graph client can try to recreate a session and resume the work. Further access to the session specified in the failed request is not expected.
Please Check if the below work arounds help in your case:
1)
use the CreateSession method > workbook: createSession | Microsoft Docs to get the workbook info, and set the persistChanges setting.
=>(Set var persistChanges = true; )
Code:
var persistChanges = true;
try
{
WorkbookSessionInfo res = await _graphServiceClient.Groups[_groupId].Drive.Items[productStructureCalculator.CalculatorId].Workbook
.CreateSession(persistChanges)
.Request()
.Header("Prefer", "respond-async")
.PostAsync();
var result = res;
return result;
}
catch (Exception ex)
{
Console.WriteLine($"Error getting items: {ex.Message}");
return null;
}
Reference-SO
Or
2)
You can set the Timeout to a higher value .Lets say one hour:
graphServiceClient.HttpProvider.OverallTimeout = TimeSpan.FromHours(1);
Or
3)
Add session in start up class
Ex:
services.AddSession(options => {
options.IdleTimeout = TimeSpan.FromMinutes(30);
options.Cookie.HttpOnly = true;
options.Cookie.IsEssential = true;
At least chance, take a look at activityBasedTimeoutPolicy which Represents a policy that can control the idle timeout for web sessions for applications that support activity-based timeout functionality.
I'm doing azure function which should regularly get ad reports from Google Ads API and save it to CSV.
Copying code from Google documentation left me with this
public static void Run([TimerTrigger("0 22 12 * * *")] TimerInfo myTimer, ILogger log)
{
log.LogInformation($"C# Timer trigger function executed at: {DateTime.Now}");
RunRequest(new GoogleAdsClient(new GoogleAdsConfig() {
DeveloperToken = "/*token*/",
OAuth2Mode = OAuth2Flow.SERVICE_ACCOUNT,
OAuth2PrnEmail = "/*service account email*/",
OAuth2SecretsJsonPath = "/*service account json*/"
}), "/*client id*/", log);
}
public static void RunRequest(GoogleAdsClient client, string customerId, ILogger log)
{
// Get the GoogleAdsService.
GoogleAdsServiceClient googleAdsService = client.GetService(
Services.V5.GoogleAdsService);
// Create the query.
string query = #"/*request*/";
try
{
// Issue a search request.
googleAdsService.SearchStream(customerId, query,
delegate (SearchGoogleAdsStreamResponse resp)
{
using var writer = new StreamWriter($"reports\\report{DateTime.Now}.csv");
using var csv = new CsvWriter(writer, CultureInfo.InvariantCulture);
csv.WriteRecords(Report.BuildReports(resp.Results));
}
);
}
catch (GoogleAdsException e)
{
log.LogInformation("Failure:");
log.LogInformation($"Message: {e.Message}");
log.LogInformation($"Failure: {e.Failure}");
log.LogInformation($"Request ID: {e.RequestId}");
throw;
}
}
Executing this code gives me an exception with this content:
"Status(StatusCode="Unauthenticated", Detail="Request is missing required authentication credential. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project."
As I understand I don't need OAuth2 access token when using service account. How to fix this problem, what am I missing?
As mentioned in the authorization section of the reference documentation, you can only use service accounts if you have a G Suite (now called Google Workspace) domain.
You'll need to set up domain-wide delegation for the given OAuth client and then do a user impersonation for a G Suite account that has access to the Google Ads accounts you need to work with.
I am trying to connect to my couchbase server (Enterprise ver 4.6.2) and open a bucket using the .Net SDK, the code is very simple but still fail to work:
var cluster = new Cluster(new ClientConfiguration
{
Servers = new List<Uri> { new Uri("https://10.0.0.54:8091/") }
});
try
{
var bucket = cluster.OpenBucket("default");
}
catch (Exception ex)
{
Console.WriteLine("Error getting bucket.");
Console.WriteLine(ex.Message);
}
The inner exception details I get:
Message
Object reference not set to an instance of an object
StackTrace
Couchbase.IO.Services.PooledIOService.CheckEnabledServerFeatures(IConnection connection)
at Couchbase.IO.Services.PooledIOService..ctor(IConnectionPool connectionPool)
at Couchbase.IO.IOServiceFactory.<>c__DisplayClass0_0.<GetFactory>b__0(IConnectionPool pool)
at Couchbase.Configuration.Server.Providers.CarrierPublication.CarrierPublicationProvider.GetConfig(String bucketName, String username, String password)
The main exception I see is:
Could not bootstrap - check inner exceptions for details.
And the stack trace:
at Couchbase.Core.ClusterController.CreateBucket(String bucketName, String username, String password, IAuthenticator authenticator)
at Couchbase.Core.ClusterController.CreateBucket(String bucketName, IAuthenticator authenticator)
at Couchbase.Cluster.OpenBucket(String bucketname)
at Couchbase.Program.Main(String[] args)
Any idea what the issue is?
I had the same problem with the Community edition. In my case I had not created the default bucket before trying to access it. Also, if your server/cluster or bucket require credentials you need to enter those as well.
Expose all required ports
docker run -d -p 8091-8096:8091-8096 -p 11210:11210 -p 11211:11211 couchbase
I'm trying to implement the DropNet library into my Windows Phone app but I'm getting the an error when calling the GetAccessTokenAsync method.
Step 1: Get the oauth token from Dropbox
public void ConnectToDropbox()
{
_client = new DropNetClient(API_KEY, API_SECRET);
_client.UseSandbox = true;
// Get Request Token (oauth token) from Dropbox
_client.GetTokenAsync(
(userLogin) =>
{
// Authorise app with Dropbox
var url = _client.BuildAuthorizeUrl();
browser.LoadCompleted += new System.Windows.Navigation.LoadCompletedEventHandler(browser_LoadCompleted);
browser.Navigate(new Uri(url));
},
(error) =>
{
Debug("Error: GetTokenAsync");
});
}
This seems to work correctly and returns an oauth authorisation code. The URL which the browser navigates to is
https://www.dropbox.com/1/oauth/authorize?oauth_token=TSLEY7lLS8K2Mmnr
Step 2: Convert the oauth token into usable Dropbox API token
void browser_LoadCompleted(object sender, System.Windows.Navigation.NavigationEventArgs e)
{
Debug("Callback URL: " + e.Uri.AbsoluteUri);
if (e.Uri.AbsolutePath == "/1/oauth/authorize")
{
//The User has logged in!
//Now to convert the Request Token into an Access Token
_client.GetAccessTokenAsync(
(response) =>
{
Debug("User is logged in");
LoadContents();
},
(error) =>
{
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
Debug("Error getting access token (GetAccessTokenAsync)");
MessageBox.Show(error.Message);
});
});
}
else
{
//Probably the login page loading, ignore
}
}
The GetAccessTokenAsync method throws the following exceptions at runtime:
An exception of type 'System.Net.WebException' occurred in System.Windows.ni.dll and wasn't handled before a managed/native boundary
The in-app MessageBox displays:
Exception of type 'DropNet.Exceptions.DropboxException' was thrown.
All the properties of the DropboxException object are as follows:
Response: RestSharp.RestResponse
Status Code: Unauthorized
Stack Trace:
Data: System.Collections.ListDictionaryInternal
Base Exception: DropNet.Exceptions.DropboxException: Exception of type 'DropNet.Exceptions.DropboxException' was thrown.
Inner Exception:
Type: DropNet.Exceptions.DropboxException
Is the the Status Code Unauthorized relevant? I'm using the appropriate API key and secret provdided by Dropbox.
I'd be grateful if anyone who's experienced similar issues when using DropNet could give me some advice in resolving this problem. Happy to provide any further info if needed.
Thanks in advance,
Andrew