OrderCloud .NET SDK API Invocation Example (Step-by-Step)

In this blog article, I cover a simple assignment of working with one of the .NET SDK OrderCloud examples. As with any API model, it is important to setup all the necessary relationships/plumbing to get the concerned code block working. So, this blog post is about the steps I took to make the concerned code block execute successfully!

As ever, a simplified representation of OrderCloud API invocation (as covered in this article):



Code Block from .NET SDK examples:

///////////////////////////////////////////////////////////////////////////////////////////////////

using OrderCloud.SDK;


var client = new OrderCloudClient(new OrderCloudClientConfig {

    ClientId = "my-client-id",

    

    // client credentials grant flow:

    ClientSecret = "my-client-secret"

    

    // OR password grant flow:

    Username = u,

    Password = p,

    

    Roles = new[] { ApiRole.OrderAdmin }

});


var orders = await client.Orders.ListAsync(OrderDirection.Incoming, filters: new { Status = OrderStatus.Open });


Console.WriteLine($"{orders.Meta.TotalCount} open orders found.");

Console.WriteLine($"Fetched page {orders.Meta.Page} of {orders.Meta.TotalPages}.");

foreach (var order in orders.Items) {

    Console.WriteLine($"ID: {order.ID}, Total: {order.Total:C}");

}

///////////////////////////////////////////////////////////////////////////////////////////////////

Step-by-Step:

Pre-requisite: Market Place

Since I decided to use the Client credentials grant flow, had to create the ClientId and ClientSecret. 

So, logon to https://portal.ordercloud.io/ and go to Seller > API Client

Create New API Client:



Provide a name and generate random client secret:



My New API Client:



So, that gives me the client id and secret for my code:



.NET Core Console App: Install OrderCloud SDK nuget package




Add the much needed client id and client secret generated from OrderCloud to the code:


Now, one of the most important pre-requisites for the above code block to work fine is to setup a default context user within the API Client:


Create a new admin user:

Seller > Admin Users

POST Create a new admin user

Request Body:

{

  "Username": "navanuser",

  "FirstName": "navan",

  "LastName": "ksr",

  "Email": "contactnavaneeth@gmail.com",

  "Active": true

}

Response:



Update API Client with Default Context User:

Seller > API Client

PUT Update an API client

Request Body:

{

  "AppName": "My API Client",

  "AccessTokenDuration": 600,

  "AllowAnyBuyer": true,

  "AllowSeller": true,

  "DefaultContextUserName": "navanuser",

  "Active": true

}

Response:




Check User Permissions

At this point, if you perform a get on the admin user - navanuser, you will find that there are no roles assigned for the user:

Seller > Admin Users

GET Get a list of admin users

Response:



POST Create a new security profile

Request:

{

  "Name": "myorderadminprofile",

  "Roles": [

    "OrderAdmin"

  ]

}

Response:



Assign necessary roles for the admin user

Seller > Admin Users

POST Create or Update a security profile assignment

Request:

{

  "SecurityProfileID": "b_4OaV6-zkmgo-turqmQNA",

  "UserID": "WshjEIexEEmxUvFne5-1oQ"

}

Now, check the assignment:

Seller > Admin Users

GET Get a list of admin users


Looks good so far!

So, time to check if the code executes fine and no wonder it does although order count is zero, which is known!



Few exceptions / Cause and solution:
 
Exception - 1:




OrderCloud.SDK.OrderCloudException
  HResult=0x80131500
  Message=invalid_grant: Default context user required for client credentials grant
  Source=OrderCloud.SDK
  StackTrace:
   at OrderCloud.SDK.OrderCloudClient.<ThrowAuthExceptionAsync>d__196.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable.ConfiguredTaskAwaiter.GetResult()
   at Flurl.Http.FlurlRequest.<HandleExceptionAsync>d__35.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()
   at Flurl.Http.FlurlRequest.<SendAsync>d__29.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at Flurl.Http.FlurlRequest.<SendAsync>d__29.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()
   at Flurl.Http.ResponseExtensions.<ReceiveJson>d__0`1.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()
   at OrderCloud.SDK.OrderCloudClient.<AuthenticateAsync>d__198.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at OrderCloud.SDK.OrderCloudClient.<AuthenticateAsync>d__186.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()
   at OrderCloud.SDK.OrderCloudClient.<EnsureTokenAsync>d__197.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable.ConfiguredTaskAwaiter.GetResult()
   at Flurl.Http.FlurlRequest.<SendAsync>d__29.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()
   at Flurl.Http.ResponseExtensions.<ReceiveJson>d__0`1.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at ConsoleApp6.Program.<Main>d__0.MoveNext() in C:\Users\conta\source\repos\ConsoleApp6\ConsoleApp6\Program.cs:line 47

  This exception was originally thrown at this call stack:
    [External Code]

Inner Exception 1:
FlurlHttpException: Call failed with status code 400 (Bad Request): POST https://sandboxapi.ordercloud.io/oauth/token

Reason:

API Client does not have a DefaultContextUserName

For instance, GET on the concerned API Client looks like this:


Solution: Execute PATCH Partially update a API Client passing API Client ID with the following request body:

{
  "DefaultContextUserName": "navanuser"
}

Exception-2:




OrderCloud.SDK.OrderCloudException
  HResult=0x80131500
  Message=Auth.InsufficientRoles: User does not have role(s) required to perform this action.
  Source=OrderCloud.SDK
  StackTrace:
   at OrderCloud.SDK.OrderCloudClient.<ThrowApiExceptionAsync>d__195.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable.ConfiguredTaskAwaiter.GetResult()
   at Flurl.Http.FlurlRequest.<HandleExceptionAsync>d__35.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()
   at Flurl.Http.FlurlRequest.<SendAsync>d__29.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at Flurl.Http.FlurlRequest.<SendAsync>d__29.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()
   at Flurl.Http.ResponseExtensions.<ReceiveJson>d__0`1.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at ConsoleApp6.Program.<Main>d__0.MoveNext() in C:\Users\conta\source\repos\ConsoleApp6\ConsoleApp6\Program.cs:line 47

  This exception was originally thrown at this call stack:
    [External Code]

Inner Exception 1:
FlurlHttpException: Call failed with status code 403 (Forbidden): GET https://sandboxapi.ordercloud.io/v1/orders/Incoming?searchType=AnyTerm&page=1&pageSize=20&Status=Open

Cause:

Security profile does not have enough permission or roles assigned to it:



Solution: Execute PUT Create or update security profile for the concerned Security Profile Id with the following request body:

{
  "Roles": [
    "OrderAdmin"
  ],
  "Name": "myorderadminprofile"
}

If Security Profile has the roles, ensure Security Profile and the concerned user are linked:

For instance, GET  Get a list of security profile assignments, notice nothing returned in the items array:


After POST Create or update a security profile assignment:

Request Body:
{
  "SecurityProfileID": "4-9b0rnQ7U6tA1Vs1YLuAA",
  "UserID": "WshjEIexEEmxUvFne5-1oQ"
}

Now, check back GET  Get a list of security profile assignments:



So, this should setup the link between the security profile and the concerned user!

References: 

https://ordercloud.io/learn/getting-started/establishing-api-access

https://stackoverflow.com/questions/69245963/ordercloud-invalid-client-error-when-using-postman-or-net-sdk


Comments

Popular Posts