How to register an new user if i have extend UserAuth table and want to fill my customer fields

Hi
I have extend UserAuth table and i want to register user now. But i find the example give me a Register POCO without my customer fields. For example, if i add “field1” in the UserAuth, how could i fill the field then register a new user. How do i register an new user ?

Could i do this smile
var newUserRegistration = new MyRegister
{
UserName = “UserName” + userId,
DisplayName = “DisplayName” + userId,
Email = “user{0}@sf.com”.Fmt(userId),
FirstName = “FirstName” + userId,
LastName = “LastName” + userId,
Password = “Password” + userId,
AutoLogin = autoLogin,
Field1 = “my customer field”
};
client.SendAsync(MyRegister);

I want to know where to fill field in the server code.

As per the previous answer.

The Register DTO’s are concrete DTO’s which can’t be extended.

Since RegisterService.cs is just a single class you can instead use your own copy of RegisterService, customized with all the additional fields you would like to add which you would then use instead of ServiceStack’s built-in Register Service.

I tried doing this (making a copy of the RegisterServce code and dropping it into my code) but I get several design time errors with the code. Has something changed since latest version of ServiceStack to be able to copy RegisterService and use that as a basis for custom code?

Otherwise, I have the same question. How do you add additional fields to UserAuth?

You can always copy the RegisterService and call that Service instead to take over User Registration. It’s all within a single RegisterService.cs source file so it should be straight forward to include ServiceStack’s dependencies and resolve any compile errors.

See this existing answer on different ways to extend ServiceStack Authentication. The first option shows how you can extend existing UserAuth by using a generic Auth Repository and specifying your own a custom UserAuth class that extends from the built-in UserAuth.

Followed the first option. Can’t seem to get it to completely work. Here’s what I added:

public class CustomUserAuth : UserAuth
{
    public Guid? Tenant { get; set; } 
}

public class CustomAuthUserSession : AuthUserSession
{
    [DataMember] public Guid? Tenant { get; set; }
}

public class AuthRepository
: OrmLiteAuthRepository<CustomUserAuth, UserAuthDetails>, IUserAuthRepository
{
    public AuthRepository(IDbConnectionFactory dbFactory)
        : base(dbFactory) { }
}

container.Register<IAuthRepository>(c => new AuthRepository(dbFactory) { UseDistinctRoleTables = true });

//Create UserAuth RDBMS Tables
container.Resolve<IAuthRepository>().InitSchema();

It adds the new “tenant” field to the resulting custom_user_auth table. but registering with that value provided does not save that value to the field, such as:

{
"username":"user",
"password":"password",
"company":"company",
"email":"someone@gmail.com",
"firstname":"First",
"lastname":"Last",
"displayname":"First Last",
"tenant":"fdf5f10faa6d4cf38ef9b05b66572d87"
}

Everything but the “tenant” value gets saved.

What am I missing?

So do I still have to copy and modify the Register service if I take the above approach? It seems if I manually update the tenant value after registration and then log in, the tenant value is now available.

I was really hoping for a cleaner solution and just using the above would work without also having to create my own Register service. Why can’t we just subclass the Register service with a custom type?

I’ll try distill the registration process further so you can see it’s not a black box and have a better understanding of what does what.

To extend the UserAuth table, you need to subclass the AuthRepository you want to use, e.g:

public class AuthRepository
    : OrmLiteAuthRepository<CustomUserAuth, UserAuthDetails>, IUserAuthRepository
{
    public AuthRepository(IDbConnectionFactory dbFactory)
        : base(dbFactory) { }
}

This tells the AuthRepository to use your data model instead of the built-in UserAuth table when saving/updating users.

The RegisterService is a built-in Service that registers new Users, it’s effectively a wrapper around calling your Auth Repository to create your Users:

The other parts RegisterService is mostly to do with Validation and AutoLogin. But you don’t need to use the built-in Register Service, you can use your own that uses a Request DTO with your additional properties that you use to populate your CustomUserAuth that you create new users with authRepo.CreateUserAuth().

All built-in Services have a fixed typed Service Contract that can’t be changed, the Register Service is no different, it doesn’t know about the additional fields in your custom UserAuth table and can’t populate them.

So you could take a copy of the RegisterService and add additional fields to your Register Request DTO which the built-in Auto Mapping will copy to your Custom UserAuth model when creating the new user in CreateUserAuth().

Session / Auth Events

The Session / Auth Events are the hooks available in different stages of the User/Auth cycle, so you could also override OnRegistered() in your Custom Auth Session to handle the OnRegistered() hook, e.g:

public class CustomAuthUserSession : AuthUserSession
{
    public override void OnRegistered(IRequest req, IAuthSession session, IServiceBase svc) 
    {
        var authRepo = req.TryResolve<IAuthRepository>();
        using (authRepo)
        {
            var userAuth = authRepo.GetUserAuth(session.UserAuthId);
            userAuth.CustomField = req.QueryString["CustomField"];
        }
    }
}

In the latest v5.5.1 on MyGet you can also intercept all Auto Mapping with the new RegisterPopulator API and manually copy over additional fields, which you can add in the Register Request DTO Meta dictionary, e.g:

AutoMapping.RegisterPopulator((CustomUserAuth userAuth, Register dto) => 
    userAuth.CustomField = dto.Meta["CustomField"]);

I’m sorry, but I really don’t like how difficult this is turning out to be. I’m essentially having to rewrite the whole registration process, which is counter productive to the idea of buying a library that already have this provided.

The problem now seems to be I can’t even use the the class name “Register” because:

‘Register’ is an ambiguous reference between ‘Acme.Platform.ServiceModel.Register’ and ‘ServiceStack.Register’ Acme.Platform.ServiceInterface C:\Users\acme\source\repos\Acme.Platform\Acme.Platform.ServiceInterface\RegisterService.cs

Can there just not be a way to extend your existing RegisterService (and related Dto’s) to included optional fields? I don’t like the Meta data option because I need this to be an actual column in the database, not a blob.

What rewrite of the whole registration process? You’re modifying a copy of an existing class which is essentially a Service around calling 1 API:

authRepo.CreateUserAuth(newUserAuth, request.Password)

This is just basic C#, obviously you have an ambiguous naming conflict with your own Register classes, so you either fully qualify the reference to refer to your own own classes, use a c# using alias directive to specify which class you want your .cs to refer to or just rename the classes so you no longer have an ambiguous reference. There’s no reason why the names of the DTO or RegisterService classes need to be the same.

How do you expect to be able to change the schema of a Type in a different Assembly in C#? That’s not possible in .NET, and since you don’t want to use the extensible dictionary fields for your additional fields you’ll need to use your own Register Request DTO with all additional properties it needs, again it just needs to copy the properties from your Request DTO into your UserAuth object and call this single API:

authRepo.CreateUserAuth(newUserAuth, request.Password)

Otherwise if you want to be able to re-use the existing built-in Register Service (which can’t possible know about your Custom Type or its additional fields) you can use the OnRegister() hook (as shown in my previous comment) and fetch it from the QueryString (or FormData):

userAuth.CustomField = req.QueryString["CustomField"];

In this case the additional fields aren’t on the built-in Register Request DTO but you can still access any additional properties from the IRequest.

Unfortunately I can’t get the RegisterService to compile, even without any changes. See my other post regarding this problem.

When I say rewrite I mean I’m having to extend basically everything related to the Register service (service, related Dto’s, auth session) just to add another field.

I would’ve thought it would be as easy as subclassing the Register dto, adding a field, passing that into RegisterService as the generic type and RegisterService using auto mapping to save/retrieve all fields in the subclassed Register dto and call it a day. Seems like the technology is there.

I’ll continue to try and make this work buy so far I’m starting to get a little agitated as to how many hours I spent on this so far with little results.

I’ve seen others asking and struggling with this same thing. Perhaps you could provide a more complete turnkey example of doing this on your website instead of just bits and pieces?

If you’re struggling with how to modify a local copy of an existing implementation, then don’t use it. Create your own Service with your own Request DTO, it only has to call the CreateUserAuth() Auth Repository API to create the User:

The simplest implementation is literally to copy the properties of your Request DTO into your UserAuth Model then call CreateUserAuth() to create the user:

public class MyRegister : IReturn<MyRegisterResponse>
{
  // my fields
}
public class MyRegisterResponse
{
    // what you want to return
    public ResponseStatus ResponseStatus { get; set; }
}

public class MyRegisterService : Service
{
    public object Post(MyRegister request)
    {
        var newUserAuth = request.ConvertTo<CustomUserAuth>();
        var user = AuthRepository.CreateUserAuth(newUserAuth, request.Password);
        return new MyRegisterResponse { /*anything you want to return e.g user.Id */ }
    }
}

You don’t need to call any hooks since you have complete control of the implementation and can add any custom logic you need in your own Service.

Ok, this seemed to work. I guess my concern is/was in doing it this way is losing any of the logic your provided RegisterService provides. But since I was able to get this basic option up and running, I will now go back through the ServiceStack RegisterService and see what may be missing that I can use and put it in.

Thanks

1 Like

The additional logic is Validation, Calling Hooks, AutoLogin if requested and a HTTP Redirect for HTML Clients (aka Browsers) if the Continue property is populated.

If you’re using your own implementation you’ll use your own Validation, you don’t need to call hooks since you can add any custom impl to your own Service and you only need AutoLogin and HTML Redirect if you need to use it - which the existing source shows how to implement.