I’m trying to learn ServiceStack and I’m hung up on an issue where my self-hosted .NET Core app just seems to hang and runs forever without responding to the browser request.
Don’t register ServiceStack Services themselves, they’re already pre-registered by ServiceStack before Configure().
ServiceStack supports both Constructor and Property injection into your Services, but don’t register generic data types like List<Pricing> in your IOC, wrap them in a Custom Type and inject that. If you need to read from your AppConfiguration you can inject AppSettings with:
public class PricingService : Service
{
public IAppSettings AppSettings { get; set; }
}
If you have both a combination of App Settings & static app configuration I’d configure them in a single class and inject that, e.g:
container.Register(c => new AppConfig(c.Resolve<IAppSettings>()) {
Pricing = new List<Pricing> {
new ProductPricing(c.Resolve<ProductRepository>()),
new TaxPricing(25m),
}
});
public class PricingService : Service
{
public AppConfig AppConfig { get; set; }
}
Don’t register ServiceStack Services themselves, they’re already pre-registered by ServiceStack before Configure() .
You mean this? I referenced that from the self-host template - how else do I specify the App Host instance?
Or should I not be extending/injecting the App Host instance myself? I referenced that from the self-host sample. How else would I bootstrap the IOC container?
Is this why the app won’t launch? (I end up with double registrations or something?)
Sorry, but it’s not clear to me what I need to change.
ServiceStack supports both Constructor and Property injection into your Services, but don’t register generic data types like List<Pricing> in your IOC, wrap them in a Custom Type and inject that.
I didn’t register List<Pricing> in the IOC - it’s wrapped in PricingService, which doesn’t need to be configurable. This is just a toy project.
Would this have any bearing on being able to launch?
(I prefer exhaustive constructors and private fields over the Service base-class or property-injections - but those are just personal preferences and design choices that shouldn’t have any bearing on being able to use the framework or the IOC, right?)
No, I mean do not register ServiceStack Services (i.e. anything that inherits/implements Service or IService) in the IOC, i.e:
/* Don't register ServiceStack Services yourself, that's what ServiceStack does
container.Register<PricingService>(c => new PricingService(
new List<Pricing> {
new ProductPricing(c.Resolve<ProductRepository>()),
new TaxPricing(25m),
}
));
*/
As this led you down the wrong track, I don’t think your remaining questions make a lot of sense. The AppHost registration is correct & you don’t create/bootstrap the IOC it’s already pre-configured and you just register any of your App dependencies in Configure() (or .NET Core’s ConfigureServices() if you prefer).
Don’t know if that’s the reason why it wont start, but you should try removing all invalid configuration first. There’s useful info in debugging, e.g. I’d enable StrictMode to see if there’s any Startup exceptions:
Env.StrictMode = true;
ServiceStack Services are autowired by ServiceStack so if you have a generic data structure in your Services constructor it tries to resolve it. Look to other solutions in my previous comment.
Everything else looks ok, if you make the changes & still doesn’t run or throw a Startup Exception of remaining issues, let me know and I’ll try run it locally.
Ah! Sorry, by “ServiceStack services”, I thought you meant the framework’s built-in services that come pre-registered. I didn’t realize implementing IService caused it to register them for me.
There’s a couple of reasons I’d prefer it didn’t:
I prefer having complete container bootstrapping - having certain services missing means I can’t create an IOC container myself (for example for integration testing of modular bootstrapping) and get a complete working bootstrap.
As you pointed out, constructor arguments of generic types can’t be injected - so this will somewhat color my service-architecture, e.g. having to introduce extra classes to make services compatible with auto-wiring. I’d prefer I could manually register and bootstrap all services.
Is IService marker interface used for anything other than to identify services to auto-register?
If I don’t want services auto-registered, can I omit the IService marker? If so, is there any way to manually enroll custom service registrations in the framework’s internal service registry?
(I’m very keen on the idea of being able to write and test models and services without thinking too much about the framework - to me, that’s the most promising thing about this framework. I’d prefer I could code and test my domain and then have the framework wire it up to HTTP etc. - I think that’s part of the value proposition of this framework, right?)
ServiceStack has been registering its IOC & Services the same way for 10+ years, it’s unlikely to change as it allows all other functionality to assume Services are configured & autowired the same way.
It’s an alternative if for some reason you didn’t want to use ServiceStack’s standard Service base class, as you’re new to ServiceStack I’d recommend sticking with the standard concrete Service.
No there’s no way to prevent ServiceStack from pre-registering its own Services, they’re pre-registered on Startup before Configure(). Leave ServiceStack Services as-is & focus on your App deps instead.
ServiceStack only binds & invokes its own Services (i.e. Service/IService), this behavior is fundamental as effectively the rest of the framework’s features builds its functionality around ServiceStack Services and the Request DTOs used to invoke them.
Beyond that you can delegate to your own dependencies which contains the actual implementation, but generally most people maintain their implementation within Services.
There are strategies you can adopt to automate this with your own conventions, e.g. gRPC, both AutoQuery RDBMS and AutoQuery Data as well as the new AutoCrud feature all generates their own Service implementations to either bind to an external endpoint like ASP.NET Core’s gRPC endpoints or for AutoQuery generates their own Services that effectively delegate to IAutoQueryDb and IAutoCrudDb which contains most of the generic implementation. However that requires advanced meta programming to use Reflection.Emit to dynamically code-gen the classes and so not a recommended strategy.
I’d prefer I could code and test my domain and then have the framework wire it up to HTTP etc. - I think that’s part of the value proposition of this framework
It’s not?
“ServiceStack services” are still an extra layer I have to write on top of my domain, similar to how I’d have to write controllers in an MVC framework?
(again, please don’t view this as me trying to leverage criticism - this may not be what I expected, but I am just genuinely trying to understand precisely what it is I’m going to be working with; this being a fairly open-ended framework where I might otherwise be tempted to try to go down the “wrong” path, i.e. not the “happy” path )
No binding to your internal domain isn’t a goal, the goal is to encourage web services development best practices where your Services implement your explicit Services contract defined using code-first POCO DTOs maintained in the implementation-free ServiceModel assembly. Your Service Contract shouldn’t have internal domain models, they should either be in your ServiceModel or mapped to DTOs that are.
Overall ServiceStack’s goal is to be a productive and versatile typed code-first message-based Services framework where its design enables maximum utility of your Services which can be consumed in multiple formats/endpoints whose value extends beyond the Service boundary to its rich, typed client ecosystem. It’s often opinionated, convention-based & has restrictions to retain its simplicity focus, e.g. a fundamental limitation is that each Service is called with a single Request DTO which must be unique, this restriction is what enables being able to invoke Services by sending a message. I’d encourage you to read the background concepts docs to give you a better idea of what ServiceStack is and its design goals.
You can choose to implement your Services as you wish, the only reason why I wouldn’t have my Service implementation within the Service classes is to enable DRY when implementations can be shared, but if you prefer you can have them delegate to your own classes, but IMO that’s just unnecessary boilerplate.
I’ve read most of the documentation (some of it more than once) and I’m trying to align myself with your line of thinking - at the same time, the documentation is quite abstract/conceptual in some places, so I’m also pushing to see where the concrete boundaries/limitations are.
Your answers are putting me on the right track, I think - thank you!
Okay, so I’ve moved the ServiceStack layer to a separate assembly - I’m extending Service rather than implementing IService, and I now have dedicated request/response DTOs for the ServiceStack service.
And I finally figured out why it was spinning forever - I was starting it with some default launch profile, which was launching IIS Express rather than the project itself! So the browser was on the wrong port number. D’oh. Well, so far, so good - it actually launches now.
One more thing though - on the /metadata page, everything is listed as “Required: NO”.
I’ve added <LangVersion>8.0</LangVersion> and <Nullable>enable</Nullable> to the <PropertyGroup> of every .csproj file, and none of my properties are marked as nullable.
Perhaps the framework has not (yet?) been updated with awareness of strict nulls in C# 8?
Do I have to annotate every property with [Required]?
No the code-base doesn’t have strict nulls enabled, weird to go ahead and assume every library has converted their existing code-base to use the latest language features.
It’s irrelevant regardless, ServiceStack wont be breaking every existing App by releasing a version that just starts treating string as a required property. It’s especially common for Message-based APIs to define coarse-grained Services with optional properties that is especially prevalent when organically versioning & evolving Services defensively.
Note the existing knowledge-base in docs, forums, projects & StackOverflow answers is very googable where if a presumed feature isn’t documented anywhere it doesn’t exist.
No the [Required] attribute is used by OrmLite to create non null properties which should only be annotated on Data Model DTOs, not Operation Request DTOs. You would use the Open API Attributes to further annotate your Services but this is just adds documentation, they don’t change behavior.
By default ServiceStack doesn’t enforce a validation library enabled by default, it takes care of populating your DTO and executing it through the Request Pipeline but doesn’t impose a validation library to use, by default it handles .NET Exceptions thrown within your implementation and converts them to the appropriate HTTP Error Response as per Error Handling docs.
So now the recommended way to both annotate properties as required & validate them is to use the [ValidateNotNull] attribute (equivalent to [Validate("NotNull")]). Don’t forget to register the ValidationFeature plugin.
According to the documentation, nullable vs not-nullable is distinguished from the pre-8.0 oblivious nullability state - so it is possible to support strict null-checks while keeping this feature entirely opt-in, and without affecting existing projects; even if you upgrade your codebase to C# 8.0, strict null-checks remains a per-assembly opt-in.
I think it’s entirely possible to leverage this new language feature without disrupting anything?
The new language semantics of C# 8.0 makes it possible for message publishers to specify whether or not they publish nulls, and for message consumers to specify whether or not they can handle nulls - since we’re dynamically populating DTOs, if done correctly, I think this could be extremely valuable in terms of eliminating pesky null-reference exceptions and/or noisy null guards or annotations, etc… correcting (or at least alleviating) the “billion-dollar mistake” going forward.
Just like people thoughtlessly putting interfaces in DTOs there’s a misconception that whatever’s useful for library code works well in external DTO Seriailization contracts.
As mentioned previously it’s common for coarse-grained Messages as part of organic Service development to have optional properties which is the responsibility of each individual implementation to decide how they wish to handle it, when you you don’t send a parameter for a value type like int nothing gets serialized and the DTO retains its defualt(int) initial state. Do you expect that we do the same for non-null string & other reference types and start auto-filling them in with empty strings & populating complex type properties with empty instances to match value type behavior? Or do we start special casing handling non nullable reference types and making Services more fragile by indiscriminately throwing generic serialization errors that can’t be customized? So when the next time a project is deployed an innocent flag to enable strict null checks for internal use is now going to start breaking existing API requests.
No there’s not going to be any special case handling for non-nullable reference types, both options would violate the principle of least surprise and incur a major performance hit.
Your service can choose to annotate Services on which properties are required using the Open API metadata attributes, e.g [ApiMember(IsRequired = true)]. How your Service chooses to handle when a property isn’t populated is up to it, if this is a new version of your Service you’ll likely want to populate it with a fallback value, otherwise it can return an invalid request response.
Either in C# implementation of your Service:
throw new ArgumentNullException(nameof(request.Name));
public class MyRequestValidator : AbstractValidator<MyRequest>
{
public bool MyRequestValidator()
{
RuleFor(x => x.Name).NotNull();
}
}
Or with the new declarative validation attributes which both validates & annotates your Service as required:
public class MyRequest
{
[ValidateNotNull]
public string Name { get; set; }
}
All options here support ServiceStack’s structured error handling where allows for effortless UX friendly error binding as seen in World Validation, where as an Exception at the serialization level would just result in a generic serialization error which would be different in all serializers, none AFAIK treat non-null reference types any differently, which would just make them slower & more fragile as was prevalent in WSDL/SOAP, which isn’t something you want breaking in a generic serializer, your App should decide how to handle it.
Anyway this is the last word I’m going to spend on this, wasted too much time on this already.
I’d expect data wouldn’t map to types with the wrong shape, that’s all.
I mean, you wouldn’t try to map a float value to a string property, for example. In the same sense, there are now distinct nullable and non-nullable types, and you can’t map a nullable string to a non-nullable string - they’re incompatible types. I don’t think it’s even possible to populate a non-nullable property with a null-value - I’m pretty sure the generated setter will throw? Not sure though.
But if I’ve enabled strict null-checks in a project, which is an opt-in feature, clearly I’ve done so for a reason: because I want to declare and control when I expect nulls or not. It’s my responsibility to add the ? suffix to any types that should accept nulls.
Anyhow, assuming this doesn’t change - if I were to write DTO classes with C# 8 and strict nulls, I would need to make all DTO properties nullable, correct? Doing so actually has some value either way, as far as forcing me to write null-checks in code that reads these properties, so it does provide a little more safety in that sense.
Having to declare or hand-write run-time validations just for null-checks, which you can now guard against using built-in language syntax and semantics, just seems to me like it might be a missed opportunity, that’s all.
If discussing this is a huge waste of your time, I apologize. Feel free to just ignore me.
This has no actionable meaning. A property that’s not sent isn’t mapped or populated, it’s already inert, does nothing. So all serializers are already doing the “do nothing” effect.
What? They are not separate incompatible types, they both use the same string Type. The implementation for this class:
public class C {
public string S1;
public string? S2;
}
Uses the exact same string type:
public class C
{
[System.Runtime.CompilerServices.Nullable(1)]
public string S1;
[System.Runtime.CompilerServices.Nullable(2)]
public string S2;
}
IL:
.class public auto ansi beforefieldinit C
extends [System.Private.CoreLib]System.Object
{
// Fields
.field public string S1
.custom instance void System.Runtime.CompilerServices.NullableAttribute::.ctor(uint8) = (
01 00 01 00 00
)
.field public string S2
.custom instance void System.Runtime.CompilerServices.NullableAttribute::.ctor(uint8) = (
01 00 02 00 00
)
}
They only add annotations enforced by the C# compiler, which is irrelevant in Reflection, i.e. what Serializers use to deserialize types. So using non nullable references you’ll end up with an invalid state according to your C# static analysis, e.g:
var c = (C)Activator.CreateInstance(typeof(C));
Console.WriteLine(c.S1 == c.S2 && c.S1 == null); //True
This is probably where the disconnect is as you don’t know how it’s implemented so you’re not aware of the implications of what supporting it would mean, which would require incurring a significant perf hit to use reflection to look up the annotations in a post deserialization analysis on the populated type to verify that all its non-nullable reference type properties (e.g. which would be all string types) actually had a value. The only 2 things you would do when they don’t match it’s desired state is to populate it with an empty instance or throw a serialization exception, which is what my previous comment refers to, your “do nothing” suggestion is already being done, which is going to leave your DTO inconsistent to what you’ve told your C# static to treat it as, likely leaving you with more bugs, not less.
Okay, so it doesn’t check null constraints at run-time - but then it seems even more important to have these checks being performed.
I mean, the framework is automating things that, if I were to hand-write everything (without a framework, with strict nulls) I’d get certain compile-time guarantees. The framework reduces the amount of hand-written code by solving certain problems dynamically at run-time, but I would prefer I didn’t have to think too much about compile-time vs run-time: what might or might not work or get enforced by one or the other.
I’d prefer to just think in terms of language semantics.
Also, the same perf hit is there if I have to type out the code to check them all manually - it’s just somewhere else, in my hand-written code. If I use a validation service and attributes to do it declaratively, that’s probably more net overhead than a reflection-based null enforcement, which could be cached, or generated inline as an optimization.
My bottom line is, if I’ve declared something as not nullable, I don’t expect I’d have to check it for nulls. I think anyone not knowing all the precise inner workings of the compiler and library/framework run-times, would expect the same. Why else does the language have this feature?
I’ll admit, I don’t completely understand all the technical details, and I definitely don’t have a deep understanding of the framework or the philosophy yet - if this is entirely too meaningless for you to carry on, again, just ignore me, I won’t take offence. I might be back in six months when I know a little more, or I might look back at this post and say, “what the f_ck was I thinking”.
It’s nowhere close to the same performance characteristics as a null check in compiled C# code.
Untrue as well. There’s more overhead checking for the inlined compiler generated attribute and using reflection to inspect it, the end state would be same where you’d register the same validator to check for it.
Then I think you should learn more about what guarantees the actual language feature gives you which is primarily assurances in your own code, it doesn’t magically do anything from instances created & returned by other libraries & you should never assume it does unless they’ve explicitly documented it.
Right on, yeah - it’s kind of the same as with TypeScript, then; the language has these features that can give you some extra compile-time safety, but the same language semantics don’t apply at run-time.
The main reason that surprises me is, C# was designed from the ground up as a statically-typed, compiled language - whereas with TypeScript this was obviously an afterthought.
I don’t know, I think part of this discussion is a disagreement of philosophy - like, whatever run-time facilities I design for C#, I’d personally want these facilities to leverage as much of the available metadata as possible, adhering as closely as possible to language semantics.
On the other hand, I’ve been reading about message brokers these past few days, and how basically everything is dynamic message structures and pattern matching rather than static types, so maybe that’s part of the story with a message/service-oriented framework like this.
Anyhow, thank you for entertaining this discussion - you’ve been very helpful.
C# wasn’t designed with non-nullable reference types which is why they’ve only been implemented as an annotation which the C# compiler can use to provide non-null static analysis. If they were designed from the start they would’ve been different types like Swift Optionals or Rust Option type.
Dynamic/Static isn’t really important & the lines between them are blurry, e.g. many consider Java a statically typed language but its generics is a compile-time only feature that’s erased at runtime since there’s no concept of generics in the JVM. E.g. an ArrayList<String> is the same type as an ArrayList<Integer>, i.e. just an ArrayList, so this is a valid program that runs:
ArrayList list = new ArrayList<String>();
list.add("A");
ArrayList<Integer> intList = (ArrayList<Integer>)list;
intList.add(1);
System.out.println(intList);
Which prints [A, 1].
TypeScript is similar in that it’s a statically typed language but doesn’t have its own runtime, it’s primarily a Language Service to provide type checking and static analysis to JavaScript.
It’s strictly a technical implementation issue, there’s no runtime difference between string and string? which is why you can’t use them in method overloading since they’re the same type. You’re asking for a library to implement a C# compile-time language feature but have it implemented at runtime where it’s vastly more expensive & less effective since it can only be implemented at runtime, not at compile-time which it was designed for & provides the most benefits.
If you’re going to use it on your DTOs, the only way it makes sense is that you use it in conjunction with the [ValidateNotNull] attribute to enforce runtime validation so it matches the static analysis of your code where your Service will never be called with a DTO where A is null:
public class MyRequest
{
[ValidateNotNull]
public string A { get; set; }
public string? B { get; set; }
}
And [ValidateNotNull] also expresses this as a Required Property in the Services Metadata.