AutoCRUD Preview

Hi,

Question, this feature is only helpful when you want to save entities directly sent from client…

So if you have logic to perform before or after inserting with AutoCrud, or even manitulating the saving data this is not so possible. correct?

today in my repository I do several things.

Such as.

public async Task Save(MyEntity entity){
   if(entity.SomeValue == null){
      entity.SomeValue = "Some Default"
   }
   await Db.SaveAsync(entity, true);
   this.UpdateRedisCache(entity);
   this.SendEmailToEntity(entity);
   this.RunOtherLogic();

}

When using AutoCrud im actually giving up on the ability to have complex businss logic while saving?

Thanks

So like AutoQuery, AutoCrud generates the default implementation based on your declarative Request DTO. As AutoQuery/Crud are normal ServiceStack Services you can use the same Request Filters and Filter Attributes and Fluent Validation to further apply custom logic to your Services.

Also like AutoQuery you can provide your own Custom Implementation there by taking over the implementation for that Service (i.e. AutoCrud/Query no longer generates its default implementation).

So you could take over the implementation for that Service by implementing your Service as normal:

public async Task Any(CreateMyEntity request)
{
   if(entity.SomeValue == null){
      entity.SomeValue = "Some Default"
   }
   await Db.SaveAsync(entity, true);
   this.UpdateRedisCache(entity);
   this.SendEmailToEntity(entity);
   this.RunOtherLogic();
}

When doing this you’re no longer using AutoCrud for this Service.

You could also use utilize AutoCrud APIs to implement part of your Service, e.g:

public class AutoCrudCustomServices : Service
{
    public IAutoQueryDb AutoQuery { get; set; }

    public Task Any(CreateMyEntity request)
    {
       if (entity.SomeValue == null) {
          entity.SomeValue = "Some Default"
       }

       await AutoQuery.CreateAsync(request, base.Request);

       this.UpdateRedisCache(entity);
       this.SendEmailToEntity(entity);
       this.RunOtherLogic();
    }
}

Thank you. Is many-to-one (collection) supported? Do I need to create requests for the related as well?
Thanks

There’s no special support for it, no.

So the auto crud not saving relations?

No such concept on AutoCrud Services.

Hi all the sudden i’m getting the following error while calling an AutoQuery service.

{"offset":0,"total":0,"responseStatus":{"errorCode":"NullReferenceException","message":"Object reference not set to an instance of an object.","stackTrace":"[QueryLanguages: 04/21/2020 15:42:14]:\n[REQUEST: {take:50000,fields:\"Id,Name\"}]\nSystem.NullReferenceException: Object reference not set to an instance of an object.\n   at ServiceStack.AutoQueryServiceBase.ExecAsync[From](IQueryDb`1 dto) in C:\\BuildAgent\\work\\3481147c480f4a2f\\src\\ServiceStack.Server\\AutoQueryFeature.cs:line 569\n   at ServiceStack.Host.ServiceRunner`1.ExecuteAsync(IRequest req, Object instance, TRequest requestDto) in C:\\BuildAgent\\work\\3481147c480f4a2f\\src\\ServiceStack\\Host\\ServiceRunner.cs:line 151","errors":[]}

let me know if you need more info

I’m not able to repro the issue, but the NRE is here:

using var db = AutoQuery.GetDb<From>(Request);

Are you doing anything with IAutoQueryDb? Is this a custom AutoQuery Service?

good github is back it was down for me until a minute ago :slight_smile:
No is the following

 [ValidateRequest("IsAuthenticated")]
    [ValidateRequest("[HasRole('Admin')]")]
    public class QueryLanguages : QueryDb<Language>
    {
        public int? Id { get; set; }
    }
   public class Language : AuditBase, IHasIntId
    {
        [AutoIncrement] public int Id { get; set; }
        [Unique]
        public string Name { get; set; }

        public override string ToString()
        {
            return Name;
        }
    }

The call is made trough JsonHttpClient with an apikey.

Is it all AutoQuery Services or just this Service? If it’s just this Service please provide the AuditBase class.

FYI with the latest v5.8.1 on MyGet there’s now typed [Validate*] attributes for the built-in validators where you can instead use:

[ValidateIsAuthenticated]
[ValidateHasRole("Admin")] //or [ValidateIsAdmin]
public class QueryLanguages : QueryDb<Language>
{
    public int? Id { get; set; }
}

Just checked and it is also happening on other services.
I’m not sure 100% but it happened after i clearer the cache and downloaded again.


 public interface IAudit
    {
        DateTime CreatedDate { get; set; }
        string CreatedBy { get; set; }
        DateTime ModifiedDate { get; set; }
        string ModifiedBy { get; set; }
        DateTime? SoftDeletedDate { get; set; }
        string SoftDeletedBy { get; set; }
        string SoftDeletedInfo { get; set; }
    }

    public abstract class AuditBase : IAudit
    {
        public DateTime CreatedDate { get; set; }
        [Required]
        public string CreatedBy { get; set; }

        public DateTime ModifiedDate { get; set; }
        [Required]
        public string ModifiedBy { get; set; }

        [Index] 
        public DateTime? SoftDeletedDate { get; set; }
        public string SoftDeletedBy { get; set; }
        public string SoftDeletedInfo { get; set; }
    }

Yeah still can’t repro this, tried doing a full restore on an AutoQuery .NET Core App like https://github.com/NetCoreApps/Northwind - the existing AutoQuery Services still work.

Can you try running the Northwind App locally? It uses Sqlite so has no external deps.

I’ve also tried pasting in your Service and it runs without issue, I created Languages record in Startup.cs with:

using var db = container.Resolve<IDbConnectionFactory>().Open();
if (!db.CreateTableIfNotExists<Language>()) {
    db.Insert(new Language { Name = "C#", 
        CreatedBy = "Me",   CreatedDate = DateTime.UtcNow, 
        ModifiedBy = "Me", ModifiedDate = DateTime.UtcNow, });
}

If this is still failing, try deleting all /bin and /obj in all your project folders and if that doesn’t help, try a full clean NuGet package restore again.


Edit: Also turn on strict mode Env.StrictMode = true;, maybe you have a Startup Exception causing the plugins not to be configured properly.

Ok i have tried to build a clean project with only the language entity and its working fine it is probably something to do on my real project. I have tried Env.StrictMode mode but it does not give me more insight.
I’ll need to dig deeper what is happening.

When you need to debug directly ServiceStack from another project, did you found a pratical way to have both nuget and project references?

No debugging across projects in different repos is still a poor UX with .NET Core, basically I’ve resorted to having a new solution that references all the projects I want to debug and have them reference all the *.Source.csproj projects that it depends on, instead of package references.

Basically it’s a parallel .sln with Source-only references (instead of the main package references).

Yeah i was hoping :sweat_smile: i did a lot of research but found nothing satisfying, i will try your approach in the mean time thanks for helping.

1 Like

Please let me know if you end up finding the underlying cause, in-case it’s something that needs guarding against in the framework.

Hi yeah i found a fix late yesterday night :slight_smile: basically my problem i think it was that i was registering the autoquery feature from a custom feature (Register method) which somehow made it look like it was registered, but it probably didnt initialize everything correctly.
I have moved the Plugins.Add(new AutoQueryFeature()) on the apphost as it should be.

ok cool, the problem is the plugins are already loaded when your plugin is executed so it’s too late to just a plugin to the Plugins collection which wont get loaded.

To force load a plugin from within another plugin you’d need to use IAppHost.LoadPlugin(), this same API can be used for registering/loading a plugin before or after they’ve loaded.

Good to know, yeah i was looking to previous commits and probably i didn’t notice until now because i had in a previous version of the test project the Plugins.Add(new AutoQueryFeature()) on the AppHost, my mistake that i removed it and din’t check the test project.
But it could maybe be useful on StrictMode to get an error when the sample plugin is added twice?

Some plugins support being registered multiple times, you can use the AddIfNotExists extension method to only register it if it’s not registered already:

appHost.Plugins.AddIfNotExists(new AutoQueryFeature());

There are also IAppHost.HasPlugin() and IAppHost.HasMultiplePlugins() extension methods for checking for the existence of plugins.

1 Like