My project had a structure similar to this:
- ApplicationService
- ServiceModel
- This folder contains every requests and models of the project. This is far from optimal and having a few dozen files in the same folder is a PITA.
I changed the structure to something like this:
- ApplicationService
- Contains every service (kept as is since it does not cause any issues right now)
- ServiceModel
The namespaces of the files under ServiceModel were changed to reflect the new structure and the application is working as expected. However if I try to generate the C# DTOs (http://localhost:33333/types/csharp) the generated code cannot be compiled because it cannot find the models used by the requests:
I verified and the models are present in the generated code. Which prompted me to create this post.
This is the code I used to reproduce the issue in a smaller project:
I have these requests:
using System;
using System.Net;
using CodeGen.Service.ApplicationServices;
using ServiceStack;
namespace CodeGen.Service.ServiceModel.Requests.WebHooks
{
[Api(ApiDocConstants.WebHookApi)]
[ApiResponse(HttpStatusCode.Unauthorized, ApiDocConstants.MustBeAuthenticated)]
[ApiResponse(HttpStatusCode.BadRequest, ApiDocConstants.RequestFormatIsInvalid)]
[Route("/webhooks/{Id}",
Verbs = "PUT",
Summary = "PREVIEW - Creates or updates a web hook registrations - {CreateOrUpdateWebHookRequest}",
Notes = "PREVIEW - Creates or updates a web hook registrations.")]
public class CreateOrUpdateWebHookRequest : IReturnVoid
{
public Guid Id { get; set; }
public string Trigger { get; set; }
public string Url { get; set; }
}
}
using System;
using System.Net;
using CodeGen.Service.ApplicationServices;
using ServiceStack;
namespace CodeGen.Service.ServiceModel.Requests.WebHooks
{
[Api(ApiDocConstants.WebHookApi)]
[ApiResponse(HttpStatusCode.Unauthorized, ApiDocConstants.MustBeAuthenticated)]
[ApiResponse(HttpStatusCode.BadRequest, ApiDocConstants.RequestFormatIsInvalid)]
[ApiResponse(HttpStatusCode.NotFound, ApiDocConstants.RegistrationDoesNotExist)]
[Route("/webhooks/{Id}",
Verbs = "DELETE",
Summary = "PREVIEW - Deletes a web hook registration - {DeleteWebHookRequest}",
Notes = "PREVIEW - Deletes a web hook registration.")]
public class DeleteWebHookRequest : IReturnVoid
{
public Guid Id { get; set; }
}
}
using System.Net;
using CodeGen.Service.ApplicationServices;
using CodeGen.Service.ServiceModel.WebHooks;
using ServiceStack;
namespace CodeGen.Service.ServiceModel.Requests.WebHooks
{
[Api(ApiDocConstants.WebHookApi)]
[ApiResponse(HttpStatusCode.Unauthorized, ApiDocConstants.MustBeAuthenticated)]
[Route("/webhooks",
Verbs = "GET",
Summary = "PREVIEW - Returns all web hook registrations - {GetAllWebHooksRequest}",
Notes = "PREVIEW - Returns a specific web hook registration.")]
public class GetAllWebHooksRequest : IReturn<GetAllWebHooksResponse>
{
}
}
using System;
using System.Net;
using CodeGen.Service.ApplicationServices;
using ServiceStack;
namespace CodeGen.Service.ServiceModel.Requests.WebHooks
{
[Api(ApiDocConstants.WebHookApi)]
[ApiResponse(HttpStatusCode.Unauthorized, ApiDocConstants.MustBeAuthenticated)]
[ApiResponse(HttpStatusCode.BadRequest, ApiDocConstants.RequestFormatIsInvalid)]
[ApiResponse(HttpStatusCode.NotFound, ApiDocConstants.RegistrationDoesNotExist)]
[Route("/webhooks/{Id}",
Verbs = "GET",
Summary = "PREVIEW - Returns a specific web hook registration - {GetWebHookRequest}",
Notes = "PREVIEW - Returns a specific web hook registration.")]
public class GetWebHookRequest : IReturn<WebHook>
{
public Guid Id { get; set; }
}
}
This is the DTO used by the requests:
using System.Collections.Generic;
namespace CodeGen.Service.ServiceModel.WebHooks
{
public class GetAllWebHooksResponse
{
public IReadOnlyList<WebHook> WebHooks { get; set; }
}
}
I also have an “empty” service:
class WebHookRestService : ServiceStack.Service
{
private static readonly ILog Logger = LogProvider.GetCurrentClassLogger();
public WebHookRestService()
{
}
public Task<object> Any(GetWebHookRequest request)
{
return Task.FromResult(new object());
}
public Task<GetAllWebHooksResponse> Any(GetAllWebHooksRequest request)
{
return Task.FromResult((GetAllWebHooksResponse)null);
}
public Task Any(CreateOrUpdateWebHookRequest request)
{
return Task.FromResult(3);
}
public Task Any(DeleteWebHookRequest request)
{
return Task.FromResult(new object());
}
}
When I use the VS plugin to generate C# code I obtain this generated code:
/* Options:
Date: 2016-11-21 11:48:55
Version: 4.54
Tip: To override a DTO option, remove "//" prefix before updating
BaseUrl: http://localhost:33333
//GlobalNamespace:
//MakePartial: True
//MakeVirtual: True
//MakeInternal: False
//MakeDataContractsExtensible: False
//AddReturnMarker: True
//AddDescriptionAsComments: True
//AddDataContractAttributes: False
//AddIndexesToDataMembers: False
//AddGeneratedCodeAttributes: False
//AddResponseStatus: False
//AddImplicitVersion:
//InitializeCollections: True
//IncludeTypes:
//ExcludeTypes:
//AddNamespaces:
//AddDefaultXmlNamespace: http://schemas.servicestack.net/types
*/
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.Serialization;
using ServiceStack;
using ServiceStack.DataAnnotations;
using CodeGen.Service.ServiceModel.Requests.WebHooks;
namespace CodeGen.Service.ServiceModel
{
public partial class WebHook
{
public virtual Guid Id { get; set; }
public virtual string Trigger { get; set; }
public virtual string Url { get; set; }
}
}
namespace CodeGen.Service.ServiceModel.Requests.WebHooks
{
///<summary>
///Web Hooks Registration Management
///</summary>
[Route("/webhooks/{Id}", "PUT")]
[Api("Web Hooks Registration Management")]
[ApiResponse(401, "You must be authenticated to use this request")]
[ApiResponse(400, "Request format is invalid")]
public partial class CreateOrUpdateWebHookRequest
: IReturnVoid
{
public virtual Guid Id { get; set; }
public virtual string Trigger { get; set; }
public virtual string Url { get; set; }
}
///<summary>
///Web Hooks Registration Management
///</summary>
[Route("/webhooks/{Id}", "DELETE")]
[Api("Web Hooks Registration Management")]
[ApiResponse(401, "You must be authenticated to use this request")]
[ApiResponse(400, "Request format is invalid")]
[ApiResponse(404, "Specified web hook registration does not exist")]
public partial class DeleteWebHookRequest
: IReturnVoid
{
public virtual Guid Id { get; set; }
}
///<summary>
///Web Hooks Registration Management
///</summary>
[Route("/webhooks", "GET")]
[Api("Web Hooks Registration Management")]
[ApiResponse(401, "You must be authenticated to use this request")]
public partial class GetAllWebHooksRequest
: IReturn<GetAllWebHooksResponse> // *** GetAllWebHooksResponse is not found because of a missing using
{
}
///<summary>
///Web Hooks Registration Management
///</summary>
[Route("/webhooks/{Id}", "GET")]
[Api("Web Hooks Registration Management")]
[ApiResponse(401, "You must be authenticated to use this request")]
[ApiResponse(400, "Request format is invalid")]
[ApiResponse(404, "Specified web hook registration does not exist")]
public partial class GetWebHookRequest
: IReturn<WebHook>
{
public virtual Guid Id { get; set; }
}
}
namespace CodeGen.Service.ServiceModel.WebHooks
{
public partial class GetAllWebHooksResponse
{
public virtual IReadOnlyList<WebHook> WebHooks { get; set; }
}
}
As you can see on line 85 of the generated code, the request GetAllWebHooksRequest
implements IReturn<GetAllWebHooksResponse>
however if I try to compile I get the error “The type or namespace ‘GetAllWebHooksResponse’ could not be found” :
The missing using statement is this:
using CodeGen.Service.ServiceModel.WebHooks;