November Happy Hour will be moved to Thursday December 5th.

Issue posting prices using the EPiServer.Commerce.ServiceApi

Vote:
 
I am having issues posting prices using the EPiServer.Commerce.ServiceApi. I have no issues issuing a GET, When issuing a POST with the following I receive a 500 error (also below). I have checked the permissions as directed in the setup documentation and am using an account with Admin priveliges. Error logs aren't helping either. No errors are being logged. 


Price Object:

            var newList = new List() {
                new Models.Catalog.Price ()
                {
                    PriceValueId= 6,
                    CatalogEntryCode = entryCode,
                    ApplicationId = _applicationId,
                    MarketId = "DEFAULT",
                    PriceTypeId = "AllCustomers",
                    PriceCode = String.Empty,
                    ValidFrom = DateTime.Now.AddDays(-1),
                    ValidUntil = null,
                    MinQuantity = Convert.ToDecimal(26),
                    UnitPrice = Convert.ToDecimal(160.00),
                    CurrencyCode = "USD"
                },
               new Models.Catalog.Price () {
                    PriceValueId = 5,
                    CatalogEntryCode = entryCode,
                    ApplicationId = _applicationId,
                    MarketId = "DEFAULT",
                    PriceTypeId = "AllCustomers",
                    PriceCode = String.Empty,
                    ValidFrom = DateTime.Now.AddDays(-1),
                    ValidUntil = null,
                    MinQuantity = Convert.ToDecimal(6),
                    UnitPrice = Convert.ToDecimal(162.00),
                    CurrencyCode = "USD"
                },
                new Models.Catalog.Price () {
                    PriceValueId = 4,
                    CatalogEntryCode = entryCode,
                    ApplicationId = _applicationId,
                    MarketId = "DEFAULT",
                    PriceTypeId = "AllCustomers",
                    PriceCode = String.Empty,
                    ValidFrom = DateTime.Now.AddDays(-1),
                    ValidUntil = null,
                    MinQuantity = Convert.ToDecimal(1),
                    UnitPrice = Convert.ToDecimal(165.00),
                    CurrencyCode = "USD"
                }
            };

Function:

        public List UpdatePrices(string entryCode, List prices)
        {
            try
            {
                List list = null;
                var messages = new JobMessage();

                if (_token == null) _token = GetToken(_username, _password);
                using (var client = new HttpClient() { BaseAddress = new Uri(_baseAddress) })
                {

                    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", _token.AccessToken);
                    
                    var jsonModel = JsonConvert.SerializeObject(prices);
                    var response = client.PostAsync($"/episerverapi/commerce/entries/{entryCode}/prices", new StringContent(jsonModel, Encoding.UTF8, "application/json")).Result;

                    //var msg = response.Content.ReadAsStringAsync();
                    var result = response.Content.ReadAsStringAsync().Result;
                    messages = JsonConvert.DeserializeObject(result);

                    if (response.StatusCode == HttpStatusCode.OK)
                    {
                        string json = string.Empty;

                        using (StreamReader reader = new StreamReader(response.Content.ReadAsStreamAsync().Result))
                        {
                            json = reader.ReadToEnd();
                            list = JsonConvert.DeserializeObject>(json);
                        }
                    }
                }
                return list;
            }
            catch (Exception ex)
            {
                throw;
            }
        }

Error Message that is being returned:

{   
"Message": "An error has occurred.",   
"ExceptionMessage": "Object reference not set to an instance of an object.",   
"ExceptionType": "System.NullReferenceException",   
"StackTrace": "   at EPiServer.ServiceApi.Commerce.Controllers.Catalog.PriceController.PostCatalogEntryPrice(String code, Price price)\r\n   at lambda_method(Closure , Object , Object[] )\r\n   at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c__DisplayClass10.b__9(Object instance, Object[] methodParameters)\r\n   at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ExecuteAsync(HttpControllerContext controllerContext, IDictionary`2 arguments, CancellationToken cancellationToken)\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()\r\n   at System.Web.Http.Controllers.ApiControllerActionInvoker.d__0.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()\r\n   at System.Web.Http.Controllers.ActionFilterResult.d__2.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Web.Http.Filters.AuthorizationFilterAttribute.d__2.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Web.Http.Filters.AuthorizationFilterAttribute.d__2.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()\r\n   at System.Web.Http.Controllers.AuthenticationFilterResult.d__0.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()\r\n   at System.Web.Http.Dispatcher.HttpControllerDispatcher.d__1.MoveNext()"
}
#151097
Jul 11, 2016 19:55
Vote:
 

Hi,

You can't post multiple prices at once. As the can see the function:

public virtual IHttpActionResult PostCatalogEntryPrice(string code, [FromBody]Price price)

So you need to post price one by one.

Regards,

/Q

#151105
Jul 11, 2016 23:09
Vote:
 

Yes, we had encountered the same issue recently. The Price Restful resource made us feel it accepts the collection as well, and the errror message added more weight on this. 

var result = client.PostAsync("/episerverapi/commerce/entries/{entry code}/prices", new StringContent ...



So the question is what do we benefit from price service api comparing to use price service directly?  Apart from that, the price service api does not seem triggering the event, my variants price are not updated in Find.

#151141
Edited, Jul 12, 2016 11:43
Vote:
 
<p>The ablitity to update multiple prices at once seems to be a missing feature - we will consider adding it in future releases.</p> <p>Note that the ServiceApi works in a RESTFul model. To use the priceservice directly, you will need access to the context of the site. This does mean you will need to write code in your website to handle the import. And ServiceAPI does much more than just prices.</p> <p>If you are using the default implementation of IPriceService and IPriceDetailService - it should. However, it will only trigger event if the prices are actually updated. Note that here you are using IPriceDetailService, and the prices, after optimizations, might not be changed. In that case, the event will not be triggered and the Find index will not be updated.</p> <p></p>
#151142
Jul 12, 2016 11:51
Vote:
 

Note that the ServiceApi works in a RESTFul model. To use the priceservice directly, you will need access to the context of the site. This does mean you will need to write code in your website to handle the import. And ServiceAPI does much more than just prices.

Got your point. 

Note that here you are using IPriceDetailService, and the prices, after optimizations, might not be changed. In that case, the event will not be triggered and the Find index will not be updated.

Interesting, first time I heard this "optimizations". It would be good if you can give bit more information about this. 

I think we are currently using the Price Service API to update the price, however it's not triggering the event as well. My current workround is to Enable Find Index Job interval, and let it run automatically. 

Thanks,

Vincent

#151144
Jul 12, 2016 12:10
Vote:
 

My statement above is, in fact, incorrect. Even if the optimized prices are not changed, the event will still be fired.

In your case, is ServiceAPI is running on same context with your main site? Are other changes (such as entry updates) made by ServiceAPI indexed by Find?

#151148
Edited, Jul 12, 2016 13:16
Vote:
 
<p>Hi Quan</p> <p>Thanks for your help.&nbsp;</p> <p><strong>In your case, is ServiceAPI is running on same context with your main site? Are other changes (such as entry updates) made by ServiceAPI indexed by Find?</strong></p> <p><strong></strong></p> <p>Ah ha, you are absolutely right. The ServiceAPI in our project is not running in the same context of the main site, due to some technical membership issues. If that's the case causing event was not fired, is there any workaround?</p> <p></p> <p>Vincent</p>
#151178
Jul 13, 2016 4:16
Vote:
 
<p>http://world.episerver.com/blogs/Tobias-Nilsson/Dates/2016/3/how-to-listen-to-remote-commerce-events/</p> <p>You can check out this blogpost.</p> <p>Shameless plug: This is also explain in details in my book :)</p>
#151186
Jul 13, 2016 9:53
Vote:
 

I have confirmed that I am able to post a new price thank you. I am now receiving an error using the Put Entry Price method (/episerverapi/commerce/entries/{entry code}/prices/{priceValueId}) My assumption is that this method updates the price specified. Is that correct? If not, is there a way to update prices?

Thanks.

#151251
Jul 13, 2016 15:58
Vote:
 

Yes, PutCatalogEntryPrices should update the price - but what is the error you got?

#151252
Jul 13, 2016 16:01
Vote:
 

405.0 - Method Not Allowed

Here's the function, Am I missing something?

var price = new Models.Catalog.Price ()
                {
                    PriceValueId= 6,
                    CatalogEntryCode = entryCode,
                    ApplicationId = _applicationId,
                    MarketId = "DEFAULT",
                    PriceTypeId = "AllCustomers",
                    PriceCode = String.Empty,
                    ValidFrom = DateTime.Now.AddDays(-1),
                    ValidUntil = null,
                    MinQuantity = Convert.ToDecimal(26),
                    UnitPrice = Convert.ToDecimal(160.00),
                    CurrencyCode = "USD"
                }

public Models.Catalog.Price UpdatePrice(Models.Catalog.Price price)
        {
            try
            {
                Models.Catalog.Price list = null;
                var messages = new JobMessage();
 
                if (_token == null) _token = GetToken(_username, _password);
                using (var client = new HttpClient() { BaseAddress = new Uri(_baseAddress) })
                {
 
                    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", _token.AccessToken);                    
                    var jsonModel = JsonConvert.SerializeObject(price);
                    var response = client.PutAsync($"/episerverapi/commerce/entries/{price.CatalogEntryCode}/prices/{price.PriceValueId}", new StringContent(jsonModel, Encoding.UTF8, "application/json")).Result;
                    var result = response.Content.ReadAsStringAsync().Result;
 
                    if (response.IsSuccessStatusCode)
                    {
                        string json = string.Empty;
 
                        using (StreamReader reader = new StreamReader(response.Content.ReadAsStreamAsync().Result))
                        {
                            json = reader.ReadToEnd();
                            list = JsonConvert.DeserializeObject<Models.Catalog.Price>(json);
                        }
                    }
                    else
                    {
                        messages = JsonConvert.DeserializeObject<JobMessage>(result);
                        throw new ServiceException(messages);
                    }

                }
                return list;
            }
            catch (Exception ex)    
            {
                throw;
            }
        }


#151254
Jul 13, 2016 16:06
Vote:
 

I'm not entirely sure but

client.PutAsync($"/episerverapi/commerce/entries/{price.CatalogEntryCode}/prices/{price.PriceValueId}"

Should be 

client.PutAsync("/episerverapi/commerce/entries/{entry code}/prices/{priceValueId}"

and $ character should not be there?

/Q

#151257
Edited, Jul 13, 2016 16:18
Vote:
 
<pre>client.PutAsync(<span>$"/episerverapi/commerce/entries/</span>{price.CatalogEntryCode}<span>/prices/</span>{price.PriceValueId}<span>" <br /><br />is a shorthand for the following called Composite String Formatting. the have the same end result. </span></pre> <pre>client.PutAsync(<span>string</span>.Format(<span>"/episerverapi/commerce/entries/{0}/prices/{1}"</span>,&nbsp;price.CatalogEntryCode,&nbsp;price.PriceValueId),&nbsp;</pre>
#151258
Jul 13, 2016 16:25
Vote:
 

Ah right - the C# 6 stuffs - I'm outdated now :)

What do you have in <system.webServer> - seems to me a configuration issue where PUT was not enabled.

#151260
Jul 13, 2016 16:35
Vote:
 

PUT is there.       

<add name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
<add name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />



#151262
Jul 13, 2016 16:39
Vote:
 

Mind posting the entire section here? :)

.Q

#151263
Jul 13, 2016 16:52
Vote:
 
  <system.webServer>
    <security>
      <requestFiltering>
        <requestLimits maxAllowedContentLength="524288000" />
      </requestFiltering>
    </security>
    <validation validateIntegratedModeConfiguration="false" />
    <httpErrors errorMode="Detailed">
      <remove statusCode="404" />
      <remove statusCode="500" />
      <error statusCode="404" path="/Views/ErrorHandling/ErrorHandler" responseMode="ExecuteURL" />
      <error statusCode="500" path="/Views/ErrorHandling/ErrorHandler" responseMode="ExecuteURL" />
    </httpErrors>    
    <modules runAllManagedModulesForAllRequests="true">
      <add name="InitializationModule" type="EPiServer.Framework.Initialization.InitializationModule, EPiServer.Framework" preCondition="managedHandler"/>
      <add name="UrlRewriteModule" type="EPiServer.Web.RoutingUrlRewriteModule, EPiServer" preCondition="managedHandler"/>
      <add name="ShellRoutingModule" type="EPiServer.Shell.Web.Routing.ShellRoutingModule, EPiServer.Shell"/>
      <add name="BusinessFoundationInitializeModule" preCondition="managedHandler" type="Mediachase.Commerce.Core.Modules.BusinessFoundationInitializeModule, Mediachase.Commerce"/>
      <add name="ProfileModule" type="EPiServer.Business.Commerce.HttpModules.ProfileModule, EPiServer.Business.Commerce"/>
      <add name="CatalogNodeModule" type="EPiServer.Business.Commerce.HttpModules.CatalogNodeModule, EPiServer.Business.Commerce"/>
      <add name="ErrorLog" type="EOCodeLibrary.Core.ErrorHandling.ErrorLogModule"/>
      <add name="MirroringMonitoringModule" type="EPiServer.MirroringService.MirroringMonitoring.MirroringMonitoringModule, EPiServer.Enterprise" preCondition="managedHandler" />
    </modules>
    <handlers>
      <remove name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" />
      <remove name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" />
      <remove name="ExtensionlessUrlHandler-Integrated-4.0" />      
      <add name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
      <add name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
      <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
      <add name="UrlRoutingHandler" preCondition="integratedMode" verb="*" path="UrlRouting.axd" type="System.Web.HttpForbiddenHandler, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
      <add name="ReportingHttpHandler" preCondition="integratedMode" path="Reserved.ReportViewerWebControl.axd" verb="*" type="Microsoft.Reporting.WebForms.HttpHandler, Microsoft.ReportViewer.WebForms, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
    </handlers>
    <staticContent>
      <clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="1.00:00:00" />
    </staticContent>
    <httpProtocol>
      <customHeaders>
        <remove name="X-Powered-By" />
	      <add name="X-UA-Compatible" value="IE=edge" />
      </customHeaders>
    </httpProtocol>
  </system.webServer>
#151264
Jul 13, 2016 16:54
Vote:
 

<modules> <remove name="WebDAVModule"/> </modules> <handlers> <remove name="WebDAV" /> </handlers>

These seem to be missing.

/Q

#151265
Jul 13, 2016 16:56
Vote:
 

That worked, thank you.

#151266
Jul 13, 2016 17:00
This topic was created over six months ago and has been resolved. If you have a similar question, please create a new topic and refer to this one.
* You are NOT allowed to include any hyperlinks in the post because your account hasn't associated to your company. User profile should be updated.