How to connect SAP Business One Service Layer using .NET Framework - c#

I am unable to connect SAP Business One Service Layer using .NET Framework. It throws the error Internal Server Error with status code 500.
HttpClient client = new HttpClient();
string json = JsonConvert.SerializeObject(new {
CompanyDB = "company",
UserName = "username",
Password = "password"
}
);
var response = await client.PostAsync("service layer URL", new StringContent(json,
Encoding.Default, "application/json"));
Although I am able to connect to the service layer using the .NET Core application with the same code.
I have gone through this blog https://blogs.sap.com/2015/07/15/how-to-consume-service-layer-odata-services-from-net-via-wcf/
But I am unable to Add Service Reference for the service layer.
I am not sure whether this problem belongs to the service layer or my program. Do we need to do extra code to call the OData service (as the service layer is oData V3 or V4) from the .net framework?
Please help me to solve this problem.

Regarding your login problem you could intercept the sent HTTP messages from both of your applications (.NET Framework vs. .NET Core) and compare them. For example by using Fiddler.
You might find a little difference which prevents SL from processing your request.
I was able to connect to SL successfully in a .NET Core project by using the RestSharp library. Maybe this will get you started:
private static void Main(string[] args)
{
var client = new RestClient("https://<host>:<port>/b1s/v2");
client.RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) =>
{
// allow all certificates for testing purposes
return true;
};
var resolver = new CamelCasePropertyNamesContractResolver();
// respect the names defined in the JsonProperty annotations
resolver.NamingStrategy.OverrideSpecifiedNames = false;
client.UseNewtonsoftJson(new JsonSerializerSettings() { ContractResolver = resolver });
var loginRequest = new RestRequest("Login");
loginRequest.AddJsonBody(new LoginBody() { CompanyDB = "yourCompanyDb", UserName = "user1", Password = "myPassword" });
var response = client.Post<LoginResponse>(loginRequest);
if (response.Data != null)
{
var itemRequest = new RestRequest("Items('57387')"); // get an item
// add the session cookie
itemRequest.AddHeader("Cookie", $"B1SESSION={response.Data.SessionId}");
var itemResponse = client.Get<Items>(itemRequest);
}
}
The JSON POCOs:
public class LoginBody
{
[JsonProperty("CompanyDB")]
public string CompanyDB { get; set; }
[JsonProperty("Password")]
public string Password { get; set; }
[JsonProperty("UserName")]
public string UserName { get; set; }
}
public class LoginResponse
{
[JsonProperty("SessionId")]
public string SessionId { get; set; }
}
public class Items
{
[JsonProperty("ItemCode")]
public string ItemCode { get; set; }
[JsonProperty("ItemName")]
public string ItemName { get; set; }
}
Regarding your question to add a Service Reference I am not sure what you want to achieve. If you want to generate a OData client along with all required classes and data models you might want to look at the Unchase OData Connected Service Visual Studio extension. For me this worked well since it generates a functioning SL/OData client based on the Microsoft.OData.Client.DataServiceContext class. Please see the OData client documentation for more examples on how too use it.

I wrote a library called B1SLayer that aims to make Service Layer requests a lot easier with .NET, have a look:
https://github.com/bgmulinari/B1SLayer/
https://www.nuget.org/packages/B1SLayer/
Just create your SLConnection instance and the session is managed automatically. Check the GitHub page for request samples.
var serviceLayer = new SLConnection("https://sapserver:50000/b1s/v1", "CompanyDB", "manager", "12345");

Related

Call SOAP api form c# using action, location, endpoint & namespace

I have never used soap api.
I have requirements that i have to call soap api & send response as a json(REST) api.
I have Web Service API Location(...?wsdl), Endpoint, Namespace & Soap action.
I also have username, password & other input parameters.
I am not sure how to create soap Envelope using above info & call api from c#.
Can anyone suggest me how to do it.
This is service GetRxHistory i am trying to call https://pharmacy.esihealthcaresolutions.com:9100/v4.0/RxHistoryService.svc?wsdl/GetRxHistory
First add service reference to your project using References > Add > Service Reference. In the address field enter the url for your wsdl file:
https://pharmacy.esihealthcaresolutions.com:9100/v4.0/RxHistoryService.svc?singleWsdl
You can create the client for calling this API using:
RxHistoryServiceContractClient client = new RxHistoryServiceContractClient();
You can then call various operations on the service using the client object.
client.xxxx = xxx;
client.xxx = xxx;
In your case, it would be something like this for your username and password:
client.ClientCredentials.UserName.UserName = "your username";
client.ClientCredentials.UserName.Password = "your password";
Finally, to get a response you'd write something like this:
try
{
_Client.Open();
You'd pass your request or client object here:
GetRxHistoryResponse _Response = _Client.{MethodToGetResponse}(client);
_Client.Close();
}
catch (Exception ex)
{
}
Isn't there any way to create soap envelop from data that i have?
We could use the Message class(System.ServiceModel.Channels) static method, CreateMessage method.
I have made a demo, wish it is useful to you.
class Program
{
static void Main(string[] args)
{
Product p = new Product()
{
ID = 1,
Name = "Mango"
};
Message m=Message.CreateMessage(MessageVersion.Soap12, "mymessage", p);
MessageHeader hd = MessageHeader.CreateHeader("customheader", "mynamespace", 100);
m.Headers.Add(hd);
Console.WriteLine(m);
}
}
public class Product
{
public int ID { get; set; }
public string Name { get; set; }
}
Result.
Here is an official document.
https://learn.microsoft.com/en-us/dotnet/api/system.servicemodel.channels.message.createmessage?view=netframework-4.7.2

How to use ServiceStack Redis API?

I am new to service stack redis api. So i am getting little confused while using the service stack redis api. I want to know IRedisTypedClient"<"T">"? 1) What stands for "<"T">"? 2) What are the parameters we can pass in the "<"T">"?
The IRedisTypeClient interface provides a typed version of the Redis Client API where all its API's accept a typed POCOs (i.e. Plain Old CSharp Object) for its value body which is in contrast to IRedisClient which just accepts raw strings. Behind the scenes the Typed API's just serialize the POCO's to a JSON string but it's typed API provides a nicer API to work with when dealing with rich complex types.
The API to create a IRedisTypeClient<T> is to use the IRedisClient.As<T> API, e.g:
public class Todo
{
public long Id { get; set; }
public string Content { get; set; }
public int Order { get; set; }
public bool Done { get; set; }
}
IRedisClient redis = redisManager.GetClient();
var redisTodos = redis.As<Todo>();
As seen above you can create a typed API from any user-defined POCO, which now provides API's that lets you work directly native Todo types, e.g:
var todo = new Todo
{
Id = redisTodos.GetNextSequence(),
Content = "Learn Redis",
Order = 1,
};
redisTodos.Store(todo);
Todo savedTodo = redisTodos.GetById(todo.Id);
savedTodo.Done = true;
redisTodos.Store(savedTodo);
"Updated Todo:".Print();
redisTodos.GetAll().ToList().PrintDump();
There's a stand-alone version of this example as well as a Live Demo of Backbones TODO app with a Redis backend which makes use of the RedisClient Typed API.

ServiceStack: JsonServiceClient usage without IReturn in DTO

What I would like to do is the following:
var client = new JsonServiceClient(ServiceUrl);
var request = new FooQuery {Id = 1};
IEnumerable<Project> response = client.Get(request);
However, my FooQuery doesn't implement any IReturn, and I'd like it not to (it's in a library without ServiceStack references). Here's my service side:
Library of business objects:
public class ProjectQuery
{
public int Id { get; set; }
}
AppHost:
Routes.Add<ProjectQuery>("/project", "GET");
Service:
public object Get(Foo request)
{
// do stuff.
}
Is there some nice, clean way to create the JsonServiceClient without using the IReturn interface on my business object?
Looks like there's no way not to use IReturn if you don't want to provide a URL to the JsonServiceClient Get() requests. Just decided to create another set of DTOs in my ServiceStack implementation, that are essentially mirrors of the real DTOs in another library. Then when a request comes in to my SS DTO, I create the other library's DTO, set each property, and pass it along.
Not pretty, but that's the best I could find so far.
I had the same problem using IReturn and Routes, as I wanted to use the DTOs
in assemblies with business logic, without ServiceStack references.
It worked for me, using in the Client Model
public class TestRequest
{
public int vendorId {get; set; }
public string barcode {get; set; }
public string username { get; set; }
public string password { get; set; }
}
then in the AppHost
Routes.Add<TestRequest( "/TestAPI/Reservation/{vendorId}/{barcode}"," GET,OPTIONS")
.Add<TestRequest>("/TestAPI/Reservation", "POST, OPTIONS")
and the call for JsonServiceClient with POST
request.vendorId=12344;
request.barcode="AAS1223";
TestResponse response = client.Post<TestResponse>(server_ip + "/TestAPI/Reservation", request);
OR with GET
TestResponse response = client.Get<TestResponse>(server_ip + "/TestAPI/Reservation/12344/AAS1223?username=John&password=99");
Then in the service Get or Post functions
public TestResponse Get(TestRequest request)
{
// request members hold the values of the url.
return DoBusinessLayerWork(request);
}
Using the Send() method from the JsonServiceClient type is the way to go about doing this.

re-using ServiceStack DTO in C# client

I've successfully created the Hello World example from the ServiceStack web site and modified it for my needs. Read: Basic authentication, a bit of database access. etc.
I'd like to access the hello service from the test client
[Authenticate]
[Route("/hello/{Name}")]
public class HelloRequest : IReturn<HelloResponse>
{
public string Name { get; set; }
}
public class HelloResponse
{
public string Result { get; set; }
}
public class HelloService : Service
{
public object Any(HelloRequest request)
{
var userSession = SessionAs<CustomUserSession>();
var roles = string.Join(", ", userSession.Roles.ToArray());
return new HelloResponse { Result = "Hello, " + request.Name + ", your company: " + userSession.CompanyName};
}
}
I see a few examples out there which appear to be using the "HelloRespnse" and "Hello" types, but I cannot quite figure out how one would properly import the DTO(s) created in the service. From the ServiceStack wiki:
HelloResponse response = client.Get(new Hello { Name = "World!" });
response.Result.Print();
So the summary of my question: How do I easily re-use DTOs created in my service within a C# client?
Sorry in advance for my lack of totally understanding SS and thanks for the help.
The usual way is to create a separate assembly containing just your DTO models, add a reference to this assembly to both your service implementation and client. See Recommended servicestack api structure for more info.

What is the 'api_key' and how do I use it correctly

I'm fairly new to restful services, and I've just implemented the test code to get a ServiceStack restful service going with the Swagger plugin working as well, which leads me to my question...
inside swagger-ui/index.html there is a field for 'api_key'. I know the variable name is umm... variable, and I can set it too whatever I like, but I'm slightly confused what it's used for and whether I should be making use of it.
Also, if I do use it, how does servicestack present that value to me on the server side?
Here is the Test Service I've got up and running from the documentation...
[Api("Hello Web Services")]
[Route("/Hello", Summary = #"Noel's ServiceStackSwagger thingy", Notes = "Some more info in here cause these are notes")]
[Route("/Hello/{name}", Summary = #"N031'5 ServiceStackSwagger thingy", Notes = "Some more info in here cause these are notes", Verbs="GET,POST" )]
public class Hello
{
[ApiMember(Name = "Name", Description = "This is a description", ParameterType = "path", DataType = "string", Verb="GET,POST")]
public string Name { get; set; }
}
public class HelloResponse
{
public string Result { get; set; }
}
public class HelloService : Service
{
public object Any(Hello request)
{
return new HelloResponse { Result = "Hello, " + request.Name };
}
}
to answer my own follow up request of Esker, here is how to use the API Key thingy...
public class HelloService : Service
{
public object Any(Hello request)
{
string api_key = this.Request.Headers["api_key"];
return new HelloResponse { Result = "Hello, " + request.Name };
}
}
but also required is some extra javascript to include it in the header like so (inside swagger-ui/index.html)...
$(function () {
$.ajaxSetup({
beforeSend: function (jqXHR, settings) {
jqXHR.setRequestHeader("api_key", $("#input_apiKey").val());
}
});
});
which I found in an answer in this question...
How to get Swagger to send API key as a http instead of in the URL
Swagger UI has a general concept of supplying an api_key to use in every request sent to your service, documented here. It can either be sent as a query string or header value, and you can also change the name of the parameter as described in the above link.
You only need to configure this if you actually do require an API key in your ServiceStack service (e.g. if you have a request filter that checks for and validates an API key, perhaps).
The reason you might need to configure a default API key value in the JavaScript code to set up Swagger instead of having the user type in an API key is that as soon the index.html page loads, it will send multiple requests to your service to retrieve the metadata, so it wants to know what API key value to send by default for these metadata requests before the user can begin to interact.

Categories