I'm looking to retain a ton of functionality I used to have in my codebase from the service layer that I exposed previously using OData services but through ServiceStack, assuming I implement the service logic, I don't want to have to make a ton of new DTO's for requests when this is essentially what i'm trying to achieve unless the framework "forces" me to declare a bunch of extra classes for no functional gain ...
[Route("~/{Type}")]
public class GetRequest
{
public string Type {get; set; }
public string Select { get; set; }
public string Expand { get; set; }
public string Filter { get; set; }
public string GroupBy { get; set; }
public string OrderBy { get; set; }
}
public ServiceBase<T> : Service
{
public virtual IEnumerable<T> Get(GetRequest<T> request) { ... }
}
public FooService : ServiceBase<Foo>
{
public override IEnumerable<Foo> Get(GetRequest<Foo> request) { ... }
}
The only other way I can see to implement this is to basically have to create a FooRequest DTO that inherits from the generic one here and adds nothing.
Whilst this might be the case in some scenarios, for the bulk of the hundreds of endpoints I have to migrate this just seems wasteful and likely will require to me having to result to code generation, something Service Stack claims "isn't needed".
My situation is made worse because I have "multiple data contexts" to consider for example ...
// base implementation for all services, derives from ServiceStack Service
public abstract class ServiceBase<T> : Service { ... }
// core service then one concrete implementation off that
public class CoreService<T> : ServiceBase<T> { ... }
public CoreFooService : CoreService<Foo> { ... }
/// b2b service then one concrete implementation off of that
public class B2BService<T> : ServiceBase<T> { ... }
public class BarB2BService : B2BService<Bar> { ... }
... with my OData based implementation I only need to add each new class to add a point of customisation for that type of data in the stack.
With ServiceStack this still seems to be possible regarding service classes (i think, but i'm not clear on how the routing works) ... where I get confused is understanding the request DTOs which are basically the same in all get requests but seemingly not routeable based on some tpye information in the URL.
Ideally I would like to route a standard Request DTO to a service method by a combination of the HTTP verb used and then something like [Route("~/{Context}/{Type}")] in the url (with that being the attribute usage on the DTO).
I get the feeling though that ServiceStack doesn't work like this and is going to require me to define a new DTO for literally every method on every service and i'm going to have to define a bunch of new services that don't exist with no new implementation details in them just to satisfy the frameworks needs.
Or am i missing some trick in how to use the framework here to avoid this work?
You can have multiple Service base classes but your Request DTO cannot be generic, it has to be a concrete Request DTO, but it can inherit base classes, e.g. All AutoQuery RDBMS Services inherit from QueryDb<T> or QueryDb.
Your Route should start with / (i.e. not ~/) and you could have a single Parameter that accepts any Type:
[Route("/data/{Type}")]
public class GetData
{
public string Type {get; set; }
public string Select { get; set; }
public string Expand { get; set; }
public string Filter { get; set; }
public string GroupBy { get; set; }
public string OrderBy { get; set; }
}
That can be called with:
GET /data/Anything
But your Service should have the same return Type (i.e. adhere to its Service Contract) so a wildcard Service is not going to be useful unless you return the same unstructured Data response like Dictionary<string,object>, List<object>, etc.
I get the feeling though that ServiceStack doesn't work like this and is going to require me to define a new DTO for literally every method on every service and i'm going to have to define a bunch of new services that don't exist with no new implementation details in them just to satisfy the frameworks needs.
Yes ServiceStack Requires every Service is defined by its Request DTO which is the master authority describing that Services contract. This is not just a requirement to appease the Framework, the Request DTO is the message that invokes a Service, which is the only thing generic Service Clients need to send to invoke a Service, which it can't send if it doesn't exist, nor can it have a Typed API (without code-gen) if there are no types.
Related
I am new into asp.net core webAPI.
I have created a Controller method that taken a request object.
[HttpPost]
[Route("/api/DoWork")]
[ValidateModelState]
public virtual IActionResult DoWork(CustomRequest request)
{
//TODO: implement this method
}
Now this CustomRequest calss is generic class, which have multiple properties and depending upon the client/tenant will populate/set values for some of the properties.
Example :
Suppose CustomRequest class structure is,
public partial class CustomRequest
{
public string ReqId { get; set; }
public DateTime? BusinessDate { get; set; }
public DateTime? CurrentDate{ get; set; }
}
So Customer A can only set values (or send values in request) ReqId and BusinessDate and Customer B send values ReqId and CurrentDate. As to proceed with business operation either of the date is required.
It's also previously decided which client will send which of the values, and this number of properties is large.
So I was thinking of creating a relatively small class which will be subset of CustomRequest class and sufficient enough to process business operations. And I can think of two options to proceed with that.
Write code inside my controller action to create small sub set class
and then call another method that expect only the subset class
Use Custom Model binders to create that small subset class and change the method signature.
My question is:
What is the best way to handle this situation option 1 or 2 or any other option? Best way in terms of performance and customization option available (like in option 1, i don't think we can use ModelState)
Any help or guidance...
I am using swagger ui for the documentation of my ServiceStack web-services which works quite nice. However I did not find a way to add any information about the responses of those web-services (json). So when the GET method of my service looks like this:
public object Get(CustomerData customers)
{
List<CustomerDAO> customers = DataProvider.GetAllCustomers();
return customers;
}
public class CustomerDAO
{
// this is important information which needs to be visible in swagger-ui
public string Name { get; set; }
public string SomeImportantProperty { get; set; }
public string AnotherPropery { get; set; }
public string AlsoWorthDocumenting { get; set; }
// and so on...
}
I need a short description of each property in the documentation (swagger-ui) which is essential for using those web-services.
I am using ServiceStack 3.9.74 but this should also apply to the latest ServiceStack version. If not please let me know.
I was wondering how I can get this information in swagger, or if not, how to supply such important information to the developers who have to work with my web services. I am also open for any other approaches or best practices which will work in the environment of ServiceStack.
I'm not sure about your version of ServiceStack. In the latest version you would have your request dto inheirt IReturn<ReturnClassHere> which would tell swagger to look at that return class.
So your CustomerData class would look something like this:
public class CustomerData : IReturn<List<CustomerDAO>>
{
}
Although it would probably be better to setup another dto for your response that would be returned instead. Maybe something like CustomerDataResponse.
I've added an existing method to a web service (that I did not write).
I can bring the method into Soap UI by performing and update on the service.
I can run the method in SOAP UI and debug it and clearly see my method is pulling the data I want, processing it correctly but I am getting nothing back in Soap UI and my debugger terminates at that point.
Its worth nothing I build this method from an existing working method that returns data just fine. I imagine I am just missing some minor configuration some ware.
Things I have done,
1) Added the new method to the operation contract
2) Added all the necessary logic for processing the data.
I can furnish any code/configs but I just don't know what exactly is needed to troubleshoot this as I am attempting to add this off existing code. I'm generally not a vague with the details but I'm in the process of educating myself at the same time as well as trudging through some existing documentation I have found online.
The service is intended to return a class. We define a DTO and paste the results from a SQL query into our DTO. We then do some integrity checking on the DTO and test for failure or success. We then add the DTO to a container object named CustomResult based on success or failure and return the CustomResult. The CustomResult class should not need any modifying (famous last words). I did however create a new DTO class which I can add to my original post
DTO Class
namespace Custom.Company.Services
{
[DataContract]
public class TimeUnitDto
{
[DataMember]
public string Calendar { get; set; }
[DataMember]
public long AverageHour { get; set; }
[DataMember]
public long AverageDay { get; set; }
[DataMember]
public long AverageWeek { get; set; }
[DataMember]
public long AverageMonth { get; set; }
[DataMember]
public long AverageYear { get; set; }
[DataMember]
public long LookupRefreshInd { get; set; }
}
}
Thanks,
All, I figured it out. Unfortunately the answer is propriety to what I am doing but basically we the DTO to our CustomResult Class.
I copy/pasted the code from another service we use since the functionality was similar. I forgot to replace of the 'Status' assignments to the new status I created for this dto.
It was trying to place it in a Status object that the data is not going to recognize. Thanks to everyone who looked into this for me.
I'm prototyping a tool that will import files via a SOAP api to an web based application and have modelled what I'm trying to import via C# interfaces so I can wrap the web app's model data in something I can deal with.
public interface IBankAccount
{
string AccountNumber { get; set; }
ICurrency Currency { get; set; }
IEntity Entity { get; set; }
BankAccountType Type { get; set; }
}
internal class BankAccount
{
private readonly SomeExternalImplementation bankAccount;
BankAccount(SomeExternalImplementation bankAccount)
{
this.bankAccount = bankAccount;
}
// Property implementations
}
I then have a repository that returns collections of IBankAccount or whatever and a factory class to create BankAccounts for me should I need them.
My question is, it this approach going to cause me a lot of pain down the line and would it be better to create POCOs? I want to put all of this in a separate assembly and have a complete separation of data access and business logic, simply because I'm dealing with a moving target here regarding where the data will be stored online.
This is exactly the approach I use and I've never had any problems with it. In my design, anything that comes out of the data access layer is abstracted as an interface (I refer to them as data transport contracts). In my domain model I then have static methods to create business entities from those data transport objects..
interface IFooData
{
int FooId { get; set; }
}
public class FooEntity
{
static public FooEntity FromDataTransport(IFooData data)
{
return new FooEntity(data.FooId, ...);
}
}
It comes in quite handy where your domain model entities gather their data from multiple data contracts:
public class CompositeEntity
{
static public CompositeEntity FromDataTransport(IFooData fooData, IBarData barData)
{
...
}
}
In contrast to your design, I don't provide factories to create concrete implementations of the data transport contracts, but rather provide delegates to write the values and let the repository worry about creating the concrete objects
public class FooDataRepository
{
public IFooData Insert(Action<IFooData> insertSequence)
{
var record = new ConcreteFoo();
insertSequence.Invoke(record as IFooData);
this.DataContext.Foos.InsertOnSubmit(record); // Assuming LinqSql in this case..
return record as IFooData;
}
}
usage:
IFooData newFoo = FooRepository.Insert(f =>
{
f.Name = "New Foo";
});
Although a factory implementation is an equally elegant solution in my opinion. To answer your question, In my experience of a very similar approach I've never come up against any major problems, and I think you're on the right track here :)
I am looking for the most appropriate way of dealing with a user activity feed on my social networking site. At the moment i have several activities which can appear on the news feed such as:
Users joins the site
User comments on a post
User adds a post to their favorites
User adds a new post to the site
Here is a simplified version of my domain objects at the moment:
public abstract class NewsItem : Entity, ITenantSpecific
{
public virtual Account Account { get; set; }
public virtual DateTime DateTime { get; set; }
// returns formatted news html string which gets
// overridden by inherted classes
public abstract string GetNewsHtml();
}
public class NewsItemJoiner : NewsItem
{
public virtual Account AccountJoined { get; set; }
public override string GetNewsHtml()
{
return "XXX has just joined our music network";
}
}
As you can see at the moment I have a property which must be overridden on each activity called GetNewsHtml. This isn't ideal as I don't believe my domain should be responsible for generating my HTML.
I have thought about using a partial view for each activity type and pass into it the NewsItem base class downcasted into the correct type.
However I am open to suggestions.
I have a similar issue but with different order types. I decided to define rendering at the view layer (web/controllers), not domain. You can do it this way:
public interface IRenderer<T> where T: NewsItem
{
string Render(T item);
}
public class NewsItemJoinerRenderer: IRenderer<NewsItemJoiner>
{
public string Render(T item)
{
return "XXX has just joined our music network";
}
}
public class NewsRendererFactory
{
public IRenderer<T> GetRenderer<T>()
{
return ServiceLocator.GetInstance<IRenderer<T>>();
}
}
Then you can pass NewsRendererFactory to controller. Perhaps there's a way to avoid ServiceLocator but for now I cannot tell.
Notice that this makes your architecture both configurable and pluggable if needed.
You can define additional render-related interfaces, add more properties to the IRenderer - for example, PartialName, etc, or have lambda filters on IRenderer that Factory uses to decide if this interface implementation is applicable for the passed (to GetRenderer("some-condition")) condition. A lot of things are possible.
If you don't want IoC containers (ServiceLocator), you can have its job done with simple switch() statement inside NewsRendererFactory.GetRenderer. This will isolate the logic inside single factory method, and you'll be able to replace it easily with true IoC once you are ready.
Update: how to get renderers.
If you don't use IoC, you do something like
typeof(IRenderer<>).Assembly.GetTypes().Where(x =>
x.IsGenericType &&
x.GetGenericTypeDefinition() == typeof(IRenderer<>) &&
x.GetGenericArguments().FirstOrDefault() == requestedTypeArguments)
Then you can select SingleOrDefault() or ToList() if you can handle multiple renderers.