ServiceStack returns UnauthorizedAccessException after usage of Route Annotation - servicestack

After annotation a dto with
[Tag("DocumentationSignoffs")]
[Route("/json/reply/DocumentationSignoffs", "GET", Summary = "Get DocumentationSignoffs", Notes = "Get DocumentationSignoffs")]
the get request returns a 403 Forbidden with:
"ResponseStatus": {
"ErrorCode": "UnauthorizedAccessException",
"Message": "Could not execute service 'GetDocumentationSignoffs', The following restrictions were not met: '\n -[LocalSubnet, External, Secure, HttpHead, HttpPost, HttpPut, HttpDelete, HttpPatch, HttpOptions, HttpOther, OneWay, Soap11, Soap12, MessageQueue, Tcp, Grpc, EndpointOther, InProcess]'\n Unauthorized call was made from: Localhost, InSecure, HttpGet, Reply, Json, Http",
"StackTrace": "System.UnauthorizedAccessException: Could not execute service 'GetDocumentationSignoffs', The following restrictions were not met: '\n -[LocalSubnet, External, Secure, HttpHead, HttpPost, HttpPut, HttpDelete, HttpPatch, HttpOptions, HttpOther, OneWay, Soap11, Soap12, MessageQueue, Tcp, Grpc, EndpointOther, InProcess]'\n Unauthorized call was made from: Localhost, InSecure, HttpGet, Reply, Json, Http\r\n bei ServiceStack.Host.ServiceController.AssertServiceRestrictions(Type requestType, RequestAttributes actualAttributes)\r\n bei ServiceStack.Host.ServiceController.<ExecuteAsync>d__53.MoveNext()\r\n--- Ende der Stapelüberwachung vom vorhergehenden Ort, an dem die Ausnahme ausgelöst wurde ---\r\n bei System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n bei System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n bei ServiceStack.Host.RestHandler.<ProcessRequestAsync>d__14.MoveNext()\r\n",
"Errors": []
}
I'am surprised. I thought I only make documentation annotations. Why is this thrown and how can I fix it? Google shows some messages where people write about Restrict Annotation. But this is not used here. I do not want that our intention for a better documentation with swagger leads to trouble/breaks the api.
C# DTO:
[Tag("DocumentationSignoffs")]
[Route("/DocumentationSignoffs", "GET", Summary = "Get DocumentationSignoffs", Notes = "Get DocumentationSignoffs")]
[DataContract]
public class DocumentationSignoffs
{
[DataMember(IsRequired = true)]
public int[] Ids { get; set; } //todo is this working? because id of signoffs should be guid
[DataMember(IsRequired = true)]
public int[] CustomerIds { get; set; }
[DataMember(IsRequired = true)]
public bool? OnlyChanged { get; set; }
[DataMember(IsRequired = true)]
public DocumentationType Type { get; set; }
[DataMember(IsRequired = true)]
public int[] SubTypeIds { get; set; }
[DataMember(IsRequired = true)]
public int? Limit { get; set; }
}
method signature of the serviceimpl
[Authenticate]
public DocumentationSignoffsResponse Get(DocumentationSignoffs request)
The Service is a partial class:
public partial class DocumentationSignoffService : BaseService
as soon as there is another partial class WITH method x the exceptions is thrown. example:
public partial class DocumentationSignoffService
{
[Authenticate]
public GetDocumentationSignoffsResponse Post(GetDocumentationSignoffs request)
{
return Get(request).ConvertTo<GetDocumentationSignoffsResponse>();
}
}
When I remove the Authenticate and the method of the second partial class the error disappeared.

Related

Issue with ServiceStack.Metadata.BaseMetadataHandler.ProcessOperations

I get the following error Sequence contains more than one matching element
when accessing an operation in my Servicestack service. (URL: /json/metadata?op=Account)
[InvalidOperationException: Sequence contains more than one matching element]
System.Linq.Enumerable.Single(IEnumerable`1 source, Func`2 predicate) +329
ServiceStack.Metadata.BaseMetadataHandler.ProcessOperations(HtmlTextWriter writer, IRequest httpReq, IResponse httpRes) +260
ServiceStack.Metadata.BaseMetadataHandler.ProcessRequest(IRequest httpReq, IResponse httpRes, String operationName) +116
ServiceStack.Host.Handlers.<>c__DisplayClass1.<CreateProcessRequestTask>b__0() +77
System.Threading.Tasks.Task.InnerInvoke() +42
System.Threading.Tasks.Task.Execute() +61
[AggregateException: One or more errors occurred.]
System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions) +45
System.Threading.Tasks.Task.Wait(Int32 millisecondsTimeout, CancellationToken cancellationToken) +111
System.Threading.Tasks.Task.Wait() +11
ServiceStack.Host.Handlers.HttpAsyncTaskHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult result) +35
System.Web.CallHandlerExecutionStep.OnAsyncHandlerCompletion(IAsyncResult ar) +100
What gives? How do I fix this issue?
The request DTO per request
[Route("/account/{Id}", Notes = "Updates the details of the account whose id is provided", Summary = "Updates account details.", Verbs = "PUT")]
[Route("/accounts", Notes = "Creates an account with the details provided.", Summary = "Creates an account.", Verbs = "POST")]
[Route("/account/{Id}", Notes = "Deletes the account whose id is provided.", Summary = "Deletes an account.", Verbs = "DELETE")]
[Route("/accounts/{Id}", Notes = "Returns the details of the account whose id is provided", Summary = "Returns account details.", Verbs = "GET")]
[Api(Description = "Update, create or delete account with the details specified.")]
public class Account
{
[ApiMember(Description = "The unique id of the account.")]
public int Id { get; set; }
[ApiMember(Description = "The id of the user who owns the account.")]
public int? OwnerId { get; set; }
[ApiMember(Description = "The account number being registered.")]
public string Number { get; set; }
[ApiMember(Description = "The type of the account. User created accounts default to bank accounts.")]
public Constants.AccountType? Type { get; set; }
[ApiMember(Description = "Defines the types of transactions for which the account may be used.")]
public Constants.AccountPurpose? Purpose { get; set; }
[ApiMember(Description = "The currency of the account.")]
public Constants.Currency? Currency { get; set; }
[ApiMember(Description = "The institution number of the Bank that provided the account number.")]
public string InstitutionNumber { get; set; }
[ApiMember(Description = "The transit tnumber of the branch that provided the account number.")]
public string TransitNumber { get; set; }
[ApiMember(Description = "Indicates whether the account holder signed a PAD agreement that allows automated withdrawals for bill payments.")]
public bool? IsPadAccount { get; set; }
}
And the response DTO
public class Account
{
public int Id { get; set; }
public User Owner { get; set; }
public User Creator { get; set; }
public Client Client { get; set; }
public string Number { get; set; }
public Constants.AccountType Type { get; set; }
public Constants.AccountPurpose Purpose { get; set; }
public Constants.Currency Currency { get; set; }
public DateTime DateCreated { get; set; }
public Constants.AccountStatus Status { get; set; }
public string InstitutionNumber { get; set; }
public string TransitNumber { get; set; }
public bool IsPadAccount { get; set; }
}
They are in different namespaces. One is Models.Account and the other is ViewModels.Account.
The issue is because your Request and Response DTO Type names need to be uniquely named.
It will work of you rename your Account Response DTO to something else, e.g:
public class AccountResponse
{
...
}
In general it's recommended for all your DTO's to be uniquely named as it's required in order for your Service Consumers to be able to use TypeScript and F# ServiceStack Reference which combine all DTO's under a single namespace. This restriction is likely to apply to future languages as well.

Servicestack routing problems

Hi i am new to servicestack
have a problem, with the the routing
i have mate a route
[Route("/Person/{ID}", "GET")]
public class GetPersonByID : IReturn<PersonResponse>
{
public decimal ObjectId { get; set; }
}
[Route("/Organization/{ID}/Person", "GET")]
public class GetPersonByOrganizationId : List<PersonResponse>
{
public decimal ObjectId { get; set; }
}
but then i am trying /Organization/281478302400588/Persons, I am getting a error saying
Unable to bind request
Stacktrace: at ServiceStack.Host.RestHandler.CreateRequest(IRequest httpReq,
IRestPath restPath) at
ServiceStack.Host.RestHandler.ProcessRequestAsync(IRequest httpReq,
IResponse httpRes, String operationName)
You need to ensure that the segment name in the route matches a property in the DTO. So {ID} should be {ObjectId}
In the second request, you should be using IReturn<List<PersonResponse>> rather than inheriting from List<PersonResponse> in your request
[Route("/Person/{ObjectId}", "GET")]
public class GetPersonByID : IReturn<PersonResponse>
{
public decimal ObjectId { get; set; }
}
[Route("/Organization/{ObjectId}/Person", "GET")]
public class GetPersonByOrganizationId : IReturn<List<PersonResponse>>
{
public decimal ObjectId { get; set; }
}
You also note you are trying /Organization/281478302400588/Persons You have used Persons in the request, but the route is Person so either change the request or the route accordingly. (Probably best on the route. i.e. [Route("/Organization/{ObjectId}/Persons", "GET")].
Then ensure in your service you are setting it up similar to this:
public class PersonService : Service
{
public PersonResponse Get(GetPersonByID request)
{
// return new PersonResponse();
}
public List<PersonResponse> Get(GetPersonByOrganizationId request)
{
// return new List<PersonResponse>();
}
}
I hope that helps.

ServiceStack "Handler for request not found" when it is working for dozens of similar DTOs

I have been using ServiceStack for months now. It has been working great for awhile and I've used many advanced approaches and Redis integration. I have a license, so my issue is not regarding a license issue, but I wonder if it is related. It almost looks like I have hit a maximum of DTO or paths, but I do not get any such error, simply the "Handler for request not found". So here is my question: how can you debug and isolate this error? I have read all the posts I can find on proper formats for DTO and DTO filters and I have been doing this long enough that I can see nothing wrong in this regard. Identically styled DTO's and paths work, but new ones fail, or so it seems. Even if I find there is something I am doing wrong in my DTO setup, the question remains, is there a way to debug this? Of course, finding what I'm doing wrong, if that is the case, is the first question.
Here is my code, AppHost first:
.Add<UsersCredentials>("/userscredentials", "GET")
.Add<UserCredential>("/userscredentials", "DELETE")
.Add<UserCredential>("/userscredentials/{UserName}", "POST PUT DELETE")
.Add<UserCredential("/userscredentials/{UserName}/(Permissions}/{System}/{ParamSet}/{Instrument}/{Interval}", "POST PUT DELETE")
DTO:
[Route("/userscredentials", "GET")]
public class UsersCredentials : IReturn<UsersCredentials>
{
public string UserName { get; set; }
public string Permissions { get; set; }
public string System { get; set; }
public uint ParamSet { get; set; }
public string Instrument { get; set; }
public uint Interval { get; set; }
} //Request DTO
[Route("/userscredentials", "DELETE")]
[Route("/userscredentials/{UserName}", "POST PUT DELETE")]
[Route("/userscredentials/{UserName}/(Permissions}/{System}/{ParamSet}/{Instrument}/{Interval}", "POST PUT DELETE")]
public class UserCredential : IReturn<UserCredential>
{
public string UserName { get; set; }
public string Permissions { get; set; }
public string System { get; set; }
public uint ParamSet { get; set; }
public string Instrument { get; set; }
public uint Interval { get; set; }
} //Request DTO
And Service:
// UsersCredentials
public class UsersCredentialsResponse
{
public string Result { get; set; }
public ResponseStatus ResponseStatus { get; set; } //Where Exceptions get auto-serialized
}
public class UsersCredentialsService : Service
{
private bool init = false;
public object Get(UsersCredentials request)
{
return (request);
}
public object Post(UserCredential request)
{
return request;
}
public object Put(UserCredential request)
{
return request;
}
public void Delete(UserCredential request)
{
}
}
I use "POSTMAN" for debug and send this as a POST:
http://sun:1300/userscredentials/a?format=json
It works. Then I send as POST:
http://sun:1300/userscredentials/a/b/c/1/d/2?format=json
and get, "Handler for Request not found: Request.HttpMethod: POST Request.PathInfo: /userscredentials/a/b/c/1/d/2 Request.QueryString: format=json Request.RawUrl: /userscredentials/a/b/c/1/d/2?format=json"
Routing:
You shouldn't be defining the routes in the AppHost using the .Add<T> method as well as using [Route("/route", "METHOD")] on the DTO.
You only need to use one method. So this may cause conflict, and certainly extra maintenance. I recommend using just the latter, of the Route attribute. So remove the Add rules from your AppHost as they are covered by the DTO routes.
You should also read the routing documentation here, and this post about routing also.
Typo:
You have a typo in your route code. You have an incorrect bracket ( instead of {:
(Permissions}
Should be:
{Permissions}
Metadata
An excellent place to check the service is defined properly is by checking the applications Metadata feature. This is enabled by default, so you can do this by adding /metadata to your server url. i.e.
http://localhost:{port}/metadata
You can see an example metadata page here
Hope that helps.

ServiceStack: Handler for request not found?

I have three routes defined. First two work fine but the last one returns error in the subject.
Routes.Add<FeeInstructionsList>("/policies/{clientPolicyId}/feeinstructions", "GET");
Routes.Add<FeeInstructionsEdit>("/policies/{clientPolicyId}/feeinstructions/{feetype}", "GET");
Routes.Add<List<FeeInstructionEditInfo>>("/policies{clientPolicyId}/feeinstructions", "POST");
When I had third route as just "/feeinstructions", it worked fine, but when I added route as above it does not work.
FeeInstructionEditInfo does not have memeber called "clientPolicyId". Could that be a reason. If so, how do I pass it to service without requiring to modify my dto. Can it be additional parameter on the service operation like this. I don't this it is possible as ss is one dto per request, but maybe there is a way?
public List<FeeInstructionEditInfo> Post(int clientPolicyId, List<FeeInstructionEditInfo> request)
Currently this method is declared as
public List<FeeInstructionEditInfo> Post(List<FeeInstructionEditInfo> request)
This is the request being sent
> POST http://localhost:12543/api/policies/680455600/feeinstructions/
> HTTP/1.1 Content-Type: application/json Accept-Language: en-US
> Referer: http://localhost:12543/ClientBin/SR.SRUnite.ShellUI.xap
> Content-Length: 1408 Accept-Encoding: identity Accept:
> application/json User-Agent: Mozilla/5.0 (compatible; MSIE 9.0;
> Windows NT 6.1; WOW64; Trident/5.0; BOIE9;ENUS) Host: localhost:12543
> Connection: Keep-Alive Pragma: no-cache
These are my original dtos, and these have not changed
[Route("/policies/{clientPolicyId}/feeinstructions/{feetype}","GET")]
public class FeeInstructionsEdit
{
public int ClientPolicyId { get; set; }
public string FeeType { get; set; }
}
public class FeeInstructionsEditResponse
{
public List<KeyValuePair> Instructions { get; set; }
public List<KeyValuePair> Contacts { get; set; }
public List<FeeInstructionEditInfo> FeeInstructions { get; set; }
}
public partial class FeeInstructionEditInfo
{
public int FeeInstructionId { get; set; }
public string FeeTypeCode { get; set; }
public string FeeTypeDescription { get; set; }
public string FeeTypeGroupCode { get; set; }
public string ProductName { get; set; }
public string InsuredType { get; set; }
public string Demographic { get; set; }
public string Instruction { get; set; }
public string Contact { get; set; }
public decimal? FeeAmount { get; set; }
}
I would post list of FeeInstructionEditInfo to /clientPolicies/342434/feeinstructions and it would not work, but posting to /feeinstructions would.
I now post using this pair of dto's.
[Route("feeinstructions","POST")]
public class FeeInstructionsSave
{
public int ClientPolicyId { get; set; }
public List<FeeInstructionEditInfo> FeeInstructions { get; set; }
}
public class FeeInstructionsSaveResponse : IHasResponseStatus
{
public ResponseStatus ResponseStatus { get; set; }
}
A fundamental concept in ServiceStack is that every service needs to be called with a Request DTO. This Request DTO can be populated with any combination of PathInfo, QueryString and Request Body.
This means if you wanted to pass in a collection you would need to have your Request DTO inherit from it, e.g:
[Route("/policies/{clientPolicyId}/feeinstructions", "POST")]
public class EditFeeInstructions : List<FeeInstructionEditInfo>
{
}
Now everything behaves as normal:
public List<FeeInstructionEditInfo> Post(EditFeeInstructions request)
{
...
}
For an Empty Request your service would look like:
public class EmptyRequest {}
public object Post(EmptyRequest request)
{
...
}
Even if you want to process the request manually yourself, you would still need to provide a Request DTO signalling your intent, e.g:
public class Hello : IRequiresRequestStream
{
//The raw Http Request Input Stream gets injected here
public Stream RequestStream { get; set; }
}

ServiceStack: Errors not serialized to responsestatus

Iam new to service stack and have been strugling for hours, trying to make servicestak work for me. For now the major show stopper is that i cann't make the exception part work. I registered all plugins by the book and services work for both REST, Soap, CSV, XML and JSV. The project contains 4 basic test methods for crud operations on a customer object. When an error is thrown i do not get the expected error: ResponseStatus is not set and a generel error is generated. Can some one please help me find out why?
https://dl.dropbox.com/u/101619220/TestingServiceStack.zip
EDIT: Thanks for comment :)
I created a simple AppHost file:
namespace TestingServiceStack
{
public class AppHost : AppHostBase
{
public AppHost()
: base("StarterTemplate ASP.NET Host", typeof(CustomersService).Assembly)
{
}
public override void Configure(Container container)
{
Plugins.Add(new ValidationFeature());
Plugins.Add(new RequestLogsFeature());
SetConfig(new EndpointHostConfig
{
DebugMode = true, //Enable StackTraces in development
});
LogManager.LogFactory = new Log4NetFactory(true);
JsConfig.EmitCamelCaseNames = true;
JsConfig.DateHandler = JsonDateHandler.ISO8601;
Routes.Add<GetCustomers>("/customers", "GET")
.Add<GetCustomers>("/customers/{Id}", "GET")
.Add<AddCustomer>("/customers", "POST")
.Add<UpdateCustomer>("/customers/{Id}", "PUT")
.Add<DeleteCustomer>("/customers/{Id}", "DELETE");
}
public static void Start()
{
new AppHost().Init();
}
}
}
And a service:
namespace TestingServiceStack
{
public class CustomersService : Service
{
#region Logging
private static readonly ILog Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
#endregion
public object Any(GetCustomers request)
{
GetCustomersResponse response = null;
try
{
if (request.Id != "0")
throw HttpError.NotFound("Id {0} throws error".Fmt(request.Id));
response = new GetCustomersResponse {Id = request.Id ?? "notset", Name = "GetCustomers"};
}
catch (Exception ex)
{
Log.Error(base.RequestContext.Get<IHttpRequest>(), ex);
throw;
}
return response;
}
public object Any(AddCustomer request)
{
return new AddCustomerResponse {Id = request.Id, Name = "AddCustomer"};
}
public object Any(UpdateCustomer request)
{
return new UpdateCustomerResponse {Id = request.Id, Name = request.Name};
}
public object Any(DeleteCustomer request)
{
return new DeleteCustomerResponse {Id = request.Id, Name = "DeleteCustomer"};
}
}
}
And the exchanged objects are:
using System.Runtime.Serialization;
using ServiceStack.ServiceInterface.ServiceModel;
namespace TestingServiceStack
{
[DataContract]
public class GetCustomers
{
[DataMember]
public string Id { get; set; }
}
[DataContract]
public class UpdateCustomer
{
[DataMember]
public string Id { get; set; }
[DataMember]
public string Name { get; set; }
}
[DataContract]
public class AddCustomer
{
[DataMember]
public string Id { get; set; }
[DataMember]
public string Name { get; set; }
}
[DataContract]
public class DeleteCustomer
{
[DataMember]
public string Id { get; set; }
}
[DataContract]
public class GetCustomersResponse : IHasResponseStatus
{
[DataMember]
public string Id { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public ResponseStatus ResponseStatus { get; set; }
}
[DataContract]
public class UpdateCustomerResponse : IHasResponseStatus
{
[DataMember]
public string Id { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public ResponseStatus ResponseStatus { get; set; }
}
[DataContract]
public class AddCustomerResponse : IHasResponseStatus
{
[DataMember]
public string Id { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public ResponseStatus ResponseStatus { get; set; }
}
[DataContract]
public class DeleteCustomerResponse : IHasResponseStatus
{
[DataMember]
public string Id { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public ResponseStatus ResponseStatus { get; set; }
}
}
I use SoapUi to call the method GetCustomers that throws an error if id equals 0, and i would expect the ResponseStatus to be set, but it isn't. When calling from SoapUi i get the following error:
I have no clue how to get reponsestatus set proberly, any hints are appreciated.
I registered all plugins by the book and services work for both REST, Soap, CSV, XML and JSV
To echo #mythz it's much easier to answer direct questions with clearly stated problems with examples of errors or exceptions. My issue with statements/generalizations like above is that I don't know what 'by the book' means nor do I know your concept of working is (could be build succeeds, metadata page is displayed, etc)
ResponseStatus is not set and a generel error is generated.
In your CustomersService class it looks you are throwing an error (HttpError) and catching/logging it. The code will then proceed to return a null response. ServiceStack has native support for throwing of exceptions. If you add a throw into your catch (assuming you want to keep the catch for logging purposes) you should get a populated ResponseStatus.
GetCustomersResponse response = null;
try
{
if (request.Id != "0")
throw HttpError.NotFound("Id {0} throws error".Fmt(request.Id));
response = new GetCustomersResponse {Id = request.Id ?? "notset", Name = "GetCustomers"};
}
catch (Exception ex)
{
Log.Error(base.RequestContext.Get<IHttpRequest>(), ex);
throw; //Let ServiceStack do its thing.
}
return response;
SoapUI
This change may fix the issue with soapUI but I'm unclear as what 'general error' you are receiving. I'm guessing the issue could be due to 'deserializing' a null response.
ServiceStack doesn't support troubleshooting with 3rd party SOAP libraries or client proxies.
See WebServicesTests.cs for examples of exceptions in integration tests. For SOAP you also want to read up on ServiceStack's SOAP Support and its limitations
We had an issue where ResponseStatus wasn't being populated - we'd decorated the Response DTO with DataContract/DataMember, but not the ResponseStatus property. Once we added that decoration, all was joyful.

Resources