I am implementing a custom solution to interface with a Magento website. My code is in C#. I am trying to create products using either the v2_soap API and the xml-rpc API web services. I have attempted to create a product using both services. I cannot seem to successfully create a product. With each service I receive the error message [102] Invalid data given. Details in error message.. I have tried passing in a variety of data to the api call, but have not had any luck. I am wondering a few things:
1) Is there any way to recieve better error messages about what data is not valid when I make a web service call? The error message seems to indicate that I can get details somewhere, but I have searched through all logs, error message data I can find with no luck.
2) What are the minimum attributes required to add a new product using the web service?
Here is a bit of the code I am using. This is the XML-RPC implementation. I am using the cook computing xml-rpc library.
public int CreateProduct(Product product) {
var entity = ConvertProduct(product);
//int productId = Service.catalogProductCreate(SessionId, "simple", "0", product.Sku, entity);
int productId = XmlRpcService.CallReturnInt(SessionId, "catalog_product.create",
new object[] {
"simple" /* product type */,
0 /* attribute set */,
product.Sku /* sku */,
entity /* product data */
});
return productId;
}
private XmlRpcStruct ConvertProduct(Product product) {
var entity = new XmlRpcStruct();
entity.Add("name", product.Name);
entity.Add("description", product.Description);
return entity;
}
protected IMagentoXmlRcpService XmlRpcService {
get {
return this.xmlRpcService;
}
}
The key was the attribute set. The default attribute set is 4 (at least for me). That little guy is the root of a lot of problems. The error responses on the Magento web services could really use some work.
See this forum thread for more info: http://www.magentocommerce.com/boards/viewthread/36892/
Related
I'm currently testing the MS Graph .NET Core SDK Client in my .NET Core 3.1 app. Purpose is to provide my own local Web API user service that performs updates/changes/fetching of users from Azure B2C AD.
In my intended solution, I will have various HTTP Client micro-services that will call API commands to my user service SDK Client, as opposed to calling the Azure Graph API using REST directly.
In my user service app, I'm trying to keep things clean by using a repository/interface approach for the actual SDK commands that are sent off to Azure. This same user service app is then returning the data back to my local HTTP Clients using my own WEB API. Imagine this user service app as the man in the middle effect.
Image below to summarize the environment:
The purpose of this is to reduce the work when changes or additions are made to the features used with the Graph Service i.e provide some standardization in comms across my own local apps and to promote better separation of concerns. Also if MS make changes to the Graph API, then I'm only updating the user service app rather than making code changes across all my HTTP Client apps. Hope that makes sense.
Anyway, now to the point! reason for my questions:
(bear with me here, I'm new to REST and using Interfaces)
Any errors encountered between the Graph SDK Client and the Graph Service API in Azure will be logged within the my user service app i.e. the extensive json error details i will capture at the first opportunity, HOWEVER I simply don't need to pass this level of detail back to all my local calling HTTP Clients.
What I'm trying to achieve is a means of identifying/capturing any HTTP Status code errors that were encountered between the SDK Client and the Graph Service, along with perhaps some basic details of the error i.e a short description and only pass these lower level details back to my local HTTP Clients i.e, keep things clean.
I'm struggling with knowing how to do this in my code, especially given the fact that i'm using an interface at the same time is making it more complex. The MS docs does give info on the list of expected error codes to be had from using the graph service, but there is no examples that explains how to process this information in order to pass the relevant (but lighter version of the info) back to another source.
Example scenario:
Local HTTP Clients call [HttpGet] GetUserById to my user service Web API
My Web API then uses the Graph SDK Client to reach out to Azure B2C, fetch the data and return.
My WEB API should then inspect the info received, if a user if found then great, return the user to my calling HTTP Client.
IF the user was not found, or perhaps a bad request was made (missing attributes / wrong user id etc) then I need to inspect the HTTP Status error code received and pass this same error code back to my calling HTTP Client, at the same time, rather than passing back the extensive json error details received from Graph Service, I just to want pass back a more simplified message, such as user not found.
The logical approach for the simplified message would be to utilize the already baked in codes messages provided by the Graph Service:
Like below: The "code" attribute is enough to explain the situation to any calling HTTP Client, if I need to investigate further then I would inspect the logs:
{
"error": {
"code": "invalidRange",
"message": "Uploaded fragment overlaps with existing data.",
"innerError": {
"requestId": "request-id",
"date": "date-time"
}
}
}
I just cant work out how to extract the HTTP Status code received from the the calls to the Graph Service through the SDK, as well as being able to fetch a single attribute from the json error message in the body and then return this reduced/simplified info back to my own HTTP Clients in the correct and conform ant manner. My own project code so far is below:
My user service WEB API Controller:
[HttpGet("{id}")]
public async Task<IActionResult> GetUserById(string id)
{
try
{
var user = await _repository.GetUserByIdAsync(id);
}
catch(Exception ex)
{
// What am I catching here? how do I get the HTTP Status Code that
was received from the call to the Graph Service in the event of an error?
// How do i extract the code error key/value from the json received from Graph Service?
}
// Finally, how do I return this captured info to the HTTP Client?
// Ignore this part, not sufficient for my needs.
//if (user == null) return BadRequest();
//if (user != null) return Ok(user);
//else return NotFound();
}
My Interface:
namespace MicrosoftGraph_API.Repository
{
public interface IGraphClientRepo
{
public Task<List<User>> GetAllUsersAsync();
public Task<User> GetUserByIdAsync(string id);
}
}
My Graph SDK Client Class:
public class GraphSDKClientRepo : IGraphClientRepo
{
public readonly IUserServiceClient _IUserServiceClient;
public GraphSDKClientRepo(IUserServiceClient userServiceClient)
{
_IUserServiceClient = userServiceClient;
}
public async Task<User> GetUserByIdAsync(string id)
{
var graphClient = _IUserServiceClient.InitializeGraphClient();
// Get user by object ID
var result = await graphClient.Users[id]
.Request()
.Select(e => new
{
e.DisplayName,
e.Id,
e.Identities
})
.GetAsync();
return result;
}
}
If your call encounters an error, the SDK will throw a ServiceException. This class includes the property you're looking for:
/// <summary>
/// The HTTP status code from the response.
/// </summary>
public System.Net.HttpStatusCode StatusCode { get; }
So your call to Graph would look something like:
public async Task<User> GetUserByIdAsync(string id)
{
var graphClient = _IUserServiceClient.InitializeGraphClient();
// Get user by object ID
try
{
return await graphClient
.Users[id]
.Request()
.Select("id,displayName,identities")
.GetAsync();
}
catch (ServiceException)
{
throw;
}
}
And you're Controller code would look something like
[HttpGet("{id}")]
public async Task<IActionResult> GetUserById(string id)
{
try
{
return this.Ok(await _repository.GetUserByIdAsync(id));
}
catch (ServiceException ex)
{
return this.StatusCode(se.StatusCode);
}
}
If you need to handle exceptions differently by HTTP Status, you can do that as well
[HttpGet("{id}")]
public async Task<IActionResult> GetUserById(string id)
{
try
{
return this.Ok(await _repository.GetUserByIdAsync(id));
}
catch (ServiceException e) when(e.StatusCode == System.Net.HttpStatusCode.NotFound)
{
//
// Do "Not Found" stuff
//
return this.StatusCode(e.StatusCode);
}
catch (ServiceException e) when(e.StatusCode == System.Net.HttpStatusCode.BadRequest)
{
//
// Do "Bad Request" stuff
//
return this.StatusCode(e.StatusCode);
}
catch (ServiceException e)
{
return this.StatusCode(e.StatusCode);
}
}
My goal: Create a Windows form app that queries via GraphQl to an existing online database.
What I've done:
To simulate a graphQl server I've followed the official graphql-node Tutorial till the end. So now I'm able to query from the GraphQl playground and get a response. This server runs on localhost:4000.
I've created a windows form app in Visual Studio that queries in graphQl to an internal database containing mocked data. E.g.
My Form.cs class contains this code, where I execute the query onButtonClick
private void button1_Click(object sender, EventArgs e)
{
var schema = Schema.For(#"
type Jedi {
name: String,
side: String,
id: ID
}
type Query {
hello: String,
jedis: [Jedi],
jedi(id: ID): Jedi
}", _ => { _.Types.Include<Query>(); }
);
var json = schema.Execute(_ =>
{
_.Query = "{jedis { name, side } }";
});
System.Diagnostics.Debug.WriteLine(json);
label1.Text = json;
}
After I execute the query my Query.cs class will recognize it and resolve the query
class Query
{
[GraphQLMetadata("jedis")]
public IEnumerable<Jedi> GetJedis()
{
return StarWarsDB.GetJedis();
}
}
This is my Current internal DB
class StarWarsDB
{
public static IEnumerable<Jedi> GetJedis()
{
return new List<Jedi>() {
new Jedi(){ Id = 1, Name ="Luke", Side="Light"},
new Jedi(){ Id = 2, Name ="Yoda", Side="Light"},
new Jedi(){ Id = 3, Name ="Darth Vader", Side="Dark"}
};
}
}
The next step i want to do:
Now, I've found a lot of examples online on how to query a db but they were always made internally in visual Studio. What I wanted to do is connecting to my personal DB running on my localHost for now (the one i made following the graphql-node Tutorial) and query it with graphQl. Then take the JSON response and print it somewhere.
You are mixing it up a little bit. For starters you don't need to have a schema declaration on your client.
If I understood you correctly you are using webforms, and want to acess a api service on the backend which will return you data.
So in that case you need a graphql "Client" in your webforms project, with which you "Connect" to a endpoint like your prisma api, and afterwards you only send querys or mutations to the api as a request.
Here is the link for the client, you install it as a nuget, and follow the documentation.
https://github.com/graphql-dotnet/graphql-client
So in most simple terms explained, graphqlClient sends a query to => endpoint(in this case your prisma api) which gets data => from your database.
Client(query) => Api(select * datasource) => DB(SQL) => Api(returns data) => Client(deserialise) => bind to UI => see the output.
GraphQL is a query language for your API, and a server-side runtime for executing queries by using a type system you define for your data. GraphQL isn't tied to any specific database or storage engine and is instead backed by your existing code and data. - graphql.org
Hi Zayed
Maybe I misunderstand your explanation but you cannot query directly to the database using GraphQL. You'll need an API project between your connection and the GraphQL logic. You'll post your GraphQL scheme to the API endpoint and it will return, based on your endpoint, the correct data structure.
I found a good website where it will be explained step by step on how to implement it in ASP.NET CORE 2.
Hope this helps.Good luck!
I am trying to create a WebHookHandler for Webhooks send from WordPress WooCommerce in ASP.NET C#.
I started with creating a ASP.NET C# Azure API App WebApplication Project and adding the relevant references (Microsoft.AspNet.WebHooks.Common, Microsoft.AspNet.WebHooks.Receivers, Microsoft.AspNet.WebHooks.Receivers.WordPress). Added the WebHookConfig, WordPressWebHookHandler and registered the WebHookConfig in the GlobalAsax.
I then published the application as an Azure App Service.
My WordPressWebHookHandler is still the default of the examples and looks like this:
public class WordPressWebHookHandler : WebHookHandler
{
public override Task ExecuteAsync(string receiver, WebHookHandlerContext context)
{
// make sure we're only processing the intended type of hook
if("WordPress".Equals(receiver, System.StringComparison.CurrentCultureIgnoreCase))
{
// todo: replace this placeholder functionality with your own code
string action = context.Actions.First();
JObject incoming = context.GetDataOrDefault<JObject>();
}
return Task.FromResult(true);
}
}
When testing a User Creation WebHook in WooCommerce I can see the request in the log as below.
But unfortunately it is never received while debugging and I see below error.
I am thinking maybe I need a custom WebHook instead of the WordPress specific one as this is a WooCommerce Webhook. Or possibly it is handled wrong in the routing and ends up in another controller.
Any help is much appreciated.
Your WebHookReceiver is wrong
There is a mismatch of expecting HTML Form Data, when in fact it should be expecting JSON.
WordPressWebHookHandler is still the default
This is what is causing your error. If you look at the WordPressWebHookReceiver, the ReceiveAsync() method implementation, calls out to ReadAsFormDataAsync() method, which is not what you want, as your Content-Type is json. So, you want to be doing ReadAsJsonAsync().
Solution: Don't use the WordPressWebHookReceiver and switch it to another one that will call ReadAsJsonAsync().
Looking at the code
I am thinking maybe I need a custom WebHook instead of the WordPress specific one as this is a WooCommerce Webhook.
You had the right idea, so I dug up some of the code to explain exactly why this was happening.
The code block below is the ReceiveAsync() method that is overridden in the WordPressWebHookReceiver. You can see that it is calling the ReadAsFormDataAsync() which is not what you want...
public override async Task<HttpResponseMessage> ReceiveAsync(
string id, HttpRequestContext context, HttpRequestMessage request)
{
...
if (request.Method == HttpMethod.Post)
{
// here is what you don't want to be called
// you want ReadAsJsonAsync(), In short, USE A DIFFERENT RECEIVER.
NameValueCollection data = await ReadAsFormDataAsync(request);
...
}
else
{
return CreateBadMethodResponse(request);
}
}
A quick search through the repository for classes that call the ReadAsJsonAsync() method, shows that the following recievers implement it:
DynamicsCrmWebHookReceiver
ZendeskWebHookReceiver
AzureAlertWebHookReceiver
KuduWebHookReceiver
MyGetWebHookReceiver
VstsWebHookReceiver
BitbucketWebHookReceiver
CustomWebHookReceiver
DropboxWebHookReceiver
GitHubWebHookReceiver
PaypalWebHookReceiver
StripeWebHookReceiver
PusherWebHookReceiver
I assumed that the CustomWebHookReceiver would fit your requirements, so can grab the NuGet here. Otherwise you can implement your own, or derive it from this class, etc.
Configuring a WebHook Recevier
(Copied from the Microsoft Documentation)
Microsoft.AspNet.WebHooks.Receivers.Custom provides support for
receiving WebHooks generated by ASP.NET WebHooks
Out of the box you can find support for Dropbox, GitHub, MailChimp,
PayPal, Pusher, Salesforce, Slack, Stripe, Trello, and WordPress but
it is possible to support any number of other providers
Initializing a WebHook Receiver
WebHook Receivers are initialized by registering them, typically in
the WebApiConfig static class, for example:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
...
// Load receivers
config.InitializeReceiveGitHubWebHooks();
}
}
There is a problem with the data format that you send in your request. You must use format of HTML Form as your error message said.
Proper POST data format is described here: How are parameters sent in an HTTP POST request?
Don't forget to set Content-Length header and correct Content-Type if your library doesn't do it. Usually the content type is application/x-www-form-urlencoded.
I would like to make some additions to Svek's answer as I now got my Proof-of-concept completed and understand a bit more about the receivers.
His answer pointed me in the right direction, but needs a little addition.
WordpressWebHookReceiver
Can take in Wordpress Webhooks of type HttpPost. This does not work with Woocommerce as Woocommerce sends Json Webhook messages and will fail the HttpPost validation which is build into the WordpressWebHookReceiver class.
CustomWebHookReceiver
Can take in custom ASP.NET Webhooks. The custom ASP.NET webhooks have a specific partner for validation which includes but is not limited to the 'ms-signature'. Even adding the header will not suffice as the signature is also used in a different way from out of the box Woocommerce to encrypt the message. Basically coming to a point that you can't integrate Woocommerce with the CustomWebHookReceiver without changing the Webhook classes of Woocommerce.
GenericWebHookReceiver
This is the receiver you want, which accepts basically a generic set of Json data and will be able to use the "code" query parameter to verify the secret which you can add in the web.config of your asp.net api application. I used this receiver to finish the Proof-of-concept and got both the signature validation as well as the deciphering of the message working right of the bat.
My basic class which I will start to build into a real solution can be viewed below and changes the JObject into a dynamic object in the methods I call from the class. As you can see I have two methods currently added, one for the customer create and one for the order create to call the respective methods which do an insert into Dynamics 365 (former CRM).
public class GenericJsonWebHookHandler : WebHookHandler
{
public GenericJsonWebHookHandler()
{
this.Receiver = "genericjson";
}
public override Task ExecuteAsync(string generator, WebHookHandlerContext context)
{
var result = false;
try
{
// Get JSON from WebHook
var data = context.GetDataOrDefault<JObject>();
if(context.Id != "crcu" && context.Id != "cror")
return Task.FromResult(true);
if (context.Id == "crcu")
{
result = WoocommerceCRMIntegrations.Entities.Contact.CreateContactInCRM(data);
}
else if (context.Id == "cror")
{
result = WoocommerceCRMIntegrations.Entities.Order.CreateOrderInCRM(data);
}
}
catch (Exception ex)
{
result = false;
}
return Task.FromResult(result);
}
}
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.
I'm facing a little problem, and I hope that you will have a solution.
I'm using a wcf service to retrieve online data (from yahoo finance).
This service calls an API which connect to yahoo in order to retrieve the data I need.
However, when I call the API, I get the error
An exception occurred during a WebClient request.
I'm calling this service from console application.
I hope that you can help me with this issue.
== Here is the code
/* wcf service Interface */
[ServiceContract]
public interface IService1
{
[OperationContract]
string GetData(int value);
// TODO: Add your service operations here
}
/* the service calls this function which belongs to another c# project */
public String updateDataBase()
{
DBHandler handler = new DBHandler();
/* Goes online et retrieve the data, when its called, the exception occurs */
handler.updateData();
return "success";
}
I solved my problem by running visual studio as Administrator.
Thank you.