For performance reasons, the preferred to call ServiceStack services for Ajax clients
is using JSON via the JSON endpoint at:
~/servicestack/json/reply/{ServiceName}
As this endpoint is just a standard JSON service we can use any ajax client to call them with. In this example we're using a light-wrapper around jQuery's $.ajax client.
//Create a ClientGateway passing in the baseUrl where your services are hosted.
var gateway = new servicestack.ClientGateway(
location.protocol + "//" + location.host + '/ServiceStack.Examples.Host.Web/ServiceStack/');
gateway.getFromService({
GetFactorial: { ForNumber: $("#txtGetFactorial").val() }
},
function(e) {
$("#serviceGetFactorial .result").html(e.Result);
});
gateway.getFromService({
GetFactorial: { ForNumber: $("#txtGetFactorial").val() }
},
function(e) {
$("#serviceGetFactorial .result").html(e.Result);
});
public class GetFactorial
{
public long ForNumber { get; set; }
}
public class GetFactorialResponse
{
public long Result { get; set; }
}
public class GetFactorialService : IService<GetFactorial>
{
public object Execute(GetFactorial request)
{
return new GetFactorialResponse { Result = GetFactorial(request.ForNumber) };
}
static long GetFactorial(long n)
{
return n > 1 ? n * GetFactorial(n - 1) : 1;
}
}
gateway.getFromService({
GetFibonacciNumbers: {
Skip: $("#txtGetFibonacciNumbersSkip").val(),
Take: $("#txtGetFibonacciNumbersTake").val()
}
},
function(e) {
var resultHtml = "<ul>";
$(e.Results).each(function(i, fibNo)
{
resultHtml += "<li>" + fibNo + "</li>";
});
resultHtml += "</ul>";
$("#serviceGetFibonacciNumbers .result").html(resultHtml);
});
public class GetFibonacciNumbers
{
public long? Skip { get; set; }
public long? Take { get; set; }
}
public class GetFibonacciNumbersResponse
{
public ArrayOfLong Results { get; set; }
}
public class GetFibonacciNumbersService
: IService<GetFibonacciNumbers>
{
private readonly ExampleConfig config;
//Example of ServiceStack's built-in Funq IOC constructor injection
public GetFibonacciNumbersService(ExampleConfig config)
{
this.config = config;
}
public object Execute(GetFibonacciNumbers request)
{
var skip = request.Skip.GetValueOrDefault(0);
var take = request.Take.GetValueOrDefault(config.DefaultFibonacciLimit);
var results = new List<long>();
var i = 0;
foreach (var fibonacciNumber in GetFibonacciNumbersNumbers())
{
if (i++ < skip) continue;
results.Add(fibonacciNumber);
if (results.Count == take) break;
}
return new GetFibonacciNumbersResponse { Results = new ArrayOfLong(results) };
}
static IEnumerable<long> GetFibonacciNumbersNumbers()
{
long n1 = 0;
long n2 = 1;
while (true)
{
var n3 = n1 + n2;
yield return n3;
n1 = n2;
n2 = n3;
}
}
}
gateway.postToService({
StoreNewUser: {
UserName: $("#txtUserName").val(),
Password: $("#txtUserName").val(),
Email: $("#txtEmail").val()
}
},
function(e) {
$("#serviceStoreNewUser .result").html(e.UserId);
var userIds = $("#txtUserIds").val();
if (userIds.length > 0) userIds += ",";
$("#txtUserIds").val(userIds + e.UserId);
},
function(ex) {
alert("Error creating new User: " + ex);
});
public class StoreNewUser
{
public string UserName { get; set; }
public string Email { get; set; }
public string Password { get; set; }
}
public class StoreNewUserResponse
{
public StoreNewUserResponse()
{
this.ResponseStatus = new ResponseStatus();
}
public long UserId { get; set; }
public ResponseStatus ResponseStatus { get; set; }
}
public class StoreNewUserService : IService<StoreNewUser>
{
//Example of ServiceStack's built-in Funq IOC property injection
public IDbConnectionFactory ConnectionFactory { get; set; }
public object Execute(StoreNewUser request)
{
using (var dbConn = ConnectionFactory.OpenDbConnection())
using (var dbCmd = dbConn.CreateCommand())
{
var existingUsers = dbCmd.Select<User>("UserName = {0}",
request.UserName).ToList();
if (existingUsers.Count > 0)
{
return new StoreNewUserResponse {
ResponseStatus = new ResponseStatus {
ErrorCode = "UserNameMustBeUnique"
}
};
}
var newUser = new User {
UserName = request.UserName,
Email = request.Email,
Password = request.Password
};
dbCmd.Insert(newUser);
return new StoreNewUserResponse { UserId = dbCmd.GetLastInsertId() };
}
}
}
gateway.getFromService({
GetUsers: { UserIds: $("#txtUserIds").val() }
},
function(e) {
var resultHtml = "<div>";
$(e.Users).each(function(i, user)
{
resultHtml += '<div class="user">'
+ user.UserName + "<br />"
+ user.Email
+ "</div>";
});
$("#serviceGetUsers .result").html(resultHtml);
});
public class GetUsers
{
public ArrayOfLong UserIds { get; set; }
public ArrayOfString UserNames { get; set; }
}
public class GetUsersResponse
{
public GetUsersResponse()
{
this.ResponseStatus = new ResponseStatus();
}
public ArrayOfUser Users { get; set; }
public ResponseStatus ResponseStatus { get; set; }
}
public class GetUsersService : IService<GetUsers>
{
//Example of ServiceStack's built-in Funq IOC property injection
public IDbConnectionFactory ConnectionFactory { get; set; }
public object Execute(GetUsers request)
{
using (var dbConn = ConnectionFactory.OpenDbConnection())
using (var dbCmd = dbConn.CreateCommand())
{
var users = new List<User>();
if (request.UserIds != null && request.UserIds.Count > 0)
{
users.AddRange(dbCmd.GetByIds<User>(request.UserIds));
}
if (request.UserNames != null && request.UserNames.Count > 0)
{
users.AddRange(dbCmd.Select<User>(
"UserName IN ({0})", request.UserNames.SqlInValues()));
}
return new GetUsersResponse { Users = new ArrayOfUser(users) };
}
}
}
One of the nice things about ServiceStack is that by using POCO classes to define your Service Interface we're able to seperate the 'message' (payload) from the communication 'channel' that delivers it.
This means that calling your services using XML is as easy as sending your request to a different end point. So calling your service via XML is as easy as:
The dynamic metadata summary page
has a complete list of web services and end points that are available.
The complete source code for this example is
viewable online
or available to download as zip package from the link below: