Base solution for your next web application

Activities of "rbarbosa"

Hi, thanks for your help, sadly this did not help, looking at the source : https://github.com/aspnetboilerplate/aspnetboilerplate/blob/dev/src/Abp.Dapper/Dapper/Repositories/DapperRepositoryBaseOfTEntityAndTPrimaryKey.cs#L102 it seems that dapper retrieves the command timeout from a parameter, which is not being passed

https://github.com/StackExchange/Dapper/blob/master/Dapper/SqlMapper.cs#L647

What i did was override DapperRepositoryBase, inject UOWManager and get the data from there

private int? CommandTimeout =>
            _unitOfWorkManager.Current?.Options.Timeout != null
                ? (int?) Convert.ToInt32(_unitOfWorkManager.Current.Options.Timeout?.TotalSeconds)
                : null;

public override Task<IEnumerable<TAny>> QueryAsync<TAny>(string query, object parameters = null)
        {
            return Connection.QueryAsync<TAny>(query, parameters, ActiveTransaction, commandTimeout: CommandTimeout);
        }

I am unsure if this is the right path but it seems to get the data where it needs to be either via attribute or with a using statement, gets a bit confusing as the attribute takes the time as INT Milliseconds, the UnitOfWorkOptions take the time as a TimeSpan, which convert to double seconds, and Dapper takes the time as Int seconds

[UnitOfWork(isTransactional: false, timeout: TIME_IN_MS)]

Eitherways it seems to solve my issue, but I am open on seeing a better way on doing this. Thanks

Hello

We have a few queries that run reports, naturally these take longer than the default 30 seconds when the user. I have tried wrapping the query in a using statement or using the UOW attribute, but when the query times out, the SqlConnection does not show the overriden value

Any ideas on how to set this up?

Adding the serviceProxyModule did not make a difference

although that did remind me that this file needs the service proxies to be added, i completely forgot about that. https://docs.aspnetzero.com/documents/aspnet-core-angular/latest/Infrastructure-Angular-NSwag Thank you

Hello I am in the process of migrating our app to ABP/Zero 7, backend went great, now on to Angular. I have created a module/folder to house all the custom code to make these upgrades less daunting:

app-routing.module.ts

{
        path: 'wms',
        loadChildren: () => import('app/wms/wms.module').then(m => m.WmsModule), //Lazy load wms module
        data: { preload: true }
}, 

Everything works fine until i have a component that uses the services through DI

routing-log.component.ts

export class RoutingLogComponent extends AppComponentBase implements OnInit {

....

    constructor(
        injector: Injector,
        private _reportService: ReportServiceProxy,
        ) {
            super(injector);
        }

        ngOnInit(): void {
                this._reportService.getReport().....
        }

....

The following error occurs when trying to load the component/page:

ERROR Error: Uncaught (in promise): NullInjectorError: StaticInjectorError(RootModule)[RoutingLogComponent -> ReportServiceProxy]: 
  StaticInjectorError(Platform: core)[RoutingLogComponent -> ReportServiceProxy]: 
    NullInjectorError: No provider for ReportServiceProxy!
NullInjectorError: StaticInjectorError(RootModule)[RoutingLogComponent -> ReportServiceProxy]: 
  StaticInjectorError(Platform: core)[RoutingLogComponent -> ReportServiceProxy]: 
    NullInjectorError: No provider for ReportServiceProxy!
    at NullInjector.push../node_modules/@angular/core/fesm5/core.js.NullInjector.get (core.js:1225)
    at resolveToken (core.js:1463)
    at tryResolveToken (core.js:1407)
    at StaticInjector.push../node_modules/@angular/core/fesm5/core.js.StaticInjector.get (core.js:1311)
    at resolveToken (core.js:1463)
    at tryResolveToken (core.js:1407)
    at StaticInjector.push../node_modules/@angular/core/fesm5/core.js.StaticInjector.get (core.js:1311)
    at resolveNgModuleDep (core.js:18446)
    at NgModuleRef_.push../node_modules/@angular/core/fesm5/core.js.NgModuleRef_.get (core.js:19135)
    at resolveNgModuleDep (core.js:18446)
    at resolvePromise (zone.js:852)
    at resolvePromise (zone.js:809)
    at zone.js:913
    at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:423)
    at Object.onInvokeTask (core.js:24328)
    at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:422)
    at Zone.push../node_modules/zone.js/dist/zone.js.Zone.runTask (zone.js:195)
    at drainMicroTaskQueue (zone.js:601)
    at ZoneTask.push../node_modules/zone.js/dist/zone.js.ZoneTask.invokeTask [as invoke] (zone.js:502)
    at invokeTask (zone.js:1693)

I have refreshed nswag and there is a service proxy file with the proper Proxy holding the api call

service-proxies.ts


@Injectable()
export class ReportServiceProxy {
    private http: HttpClient;
    private baseUrl: string;
    protected jsonParseReviver: ((key: string, value: any) => any) | undefined = undefined;

    constructor(@Inject(HttpClient) http: HttpClient, @Optional() @Inject(API_BASE_URL) baseUrl?: string) {
        this.http = http;
        this.baseUrl = baseUrl ? baseUrl : "";
    }
    .....
    .....
    ....
    }

the wms module is almost identical to the admin module in terms of what imports and declarations are being loaded to make sure i was not missing anything.

Any ideas?

Thank you @ismcagdas that solves the UOW issue. Happy new year!

However I dont seem to be able to find a way to get the index of the property's parent when an array of them are being sent, as shown here:

https://github.com/aspnetboilerplate/aspnetboilerplate/blob/master/src/Abp.Web.Api/WebApi/Validation/WebApiActionInvocationValidator.cs#L33

public void AddValidationErrors(CustomValidationContext context)
        {

            var skuManager = context.IocResolver.Resolve<ISkuManager>();
            var productTypeManager = context.IocResolver.Resolve<IProductTypeManager>();
           // var actionContext = context.IocResolver.Resolve<HttpActionContext>();
            try
            {

                AsyncHelper.RunSync(() => skuManager.ValidateDuplicateSkuAsync(Sku));
            }
            catch (UserFriendlyException e)
            {
                context.Results.Add(new ValidationResult(e.Message, new[] {"Sku" }));
            }
        }
{
    "result": null,
    "targetUrl": null,
    "success": false,
    "error": {
        "code": 0,
        "message": "Your request is not valid!",
        "details": "The following errors were detected during validation.\r\n - SKU duplicateSku already exists.\r\n - UPC: duplicateUpc already exists for a different SKU\r\n - Division: BadDivision not found.\r\n - SKU duplicateSku already exists.\r\n - UPC: duplicateUPC already exists for a different SKU\r\n",
        "validationErrors": [
            {
                "message": "SKU duplicateSku already exists.",
                "members": [
                    "sku"
                ]
            },
            {
                "message": "UPC: duplicateUpc already exists for a different SKU",
                "members": null
            },
            {
                "message": "Division: badDivision not found.",
                "members": null
            },
            {
                "message": "SKU duplicateSku already exists.",
                "members": [
                    "sku"
                ]
            },
            {
                "message": "UPC: duplicateUpc already exists for a different SKU",
                "members": null
            }
        ]
    },
    "unAuthorizedRequest": false,
    "__abp": true
}

is it better to abandon this validation style?

Started reading https://support.aspnetzero.com/QA/Questions/2583 and could not find a way to open it again.

When sending a list or array of complex objects ABP will let you know the index of the object and the property that is having issues, I am trying to use ICustomValidate to hook up to this behavior and check for duplicates on the data, among other things that need a roundtrip to the DB

eg:

    public class AddSkuInput : ICustomValidate
    {
        [MaxLength(35)]
        [Required]
        public string Sku { get; set; }
        
        
        
        public void AddValidationErrors(CustomValidationContext context)
        {
        
            var skuManager = context.IocResolver.Resolve<ISkuManager>();
            var productTypeManager = context.IocResolver.Resolve<IProductTypeManager>();

            try
            {

                AsyncHelper.RunSync(() => skuManager.ValidateDuplicateSkuAsync(Sku)); 
            }
            catch (UserFriendlyException e)
            {
                context.Results.Add(new ValidationResult(e.Message));
            }
      }
    }
    
  
      
      //for brevity this is the ValidateDuplicateSkuAsync Method
      
      public async Task ValidateDuplicateSkuAsync(string input)
        {
            if (await _skuRepository.GetAll().AnyAsync(p => p.Sku == input))
            {
                throw new UserFriendlyException($"SKU {input} already exists.");
            }
        }

With or without AsyncHelper it produces DbContext.Disposed Errors

Users normally send 100s of these items and I would like to deal with the majority of errors in batches too so I'd like to maintain the validation error structure like this response example:

{
    "result": null,
    "targetUrl": null,
    "success": false,
    "error": {
        "code": 0,
        "message": "Your request is not valid!",
        "details": "The following errors were detected during validation.\r\n - The Sku field is required.\r\n - The Upc field is required.\r\n - The Upc field is required.\r\n",
        "validationErrors": [
            {
                "message": "The Sku field is required.",
                "members": [
                    "[0].Sku"
                ]
            },
            {
                "message": "The Upc field is required.",
                "members": [
                    "[0].Upc"
                ]
            },
             {
                "message": "The Upc field is required.",
                "members": [
                    "[1].Upc"
                ]
            }
        ]
    },
    "unAuthorizedRequest": false,
    "__abp": true
}

If keeping Database access out of the DTO is a must, how can i access the ValidationContext after the method has reached the AppService (or the DomainService) as I'd like to maintain the DataAnnotations style error result through every validation process.

Hello

I have modified the code to handle the error in the pipe like so:

getReturnParameters(): void {

            this._returnAppService.validate(this.id)
            .pipe(
                //catchError cannot return void, can return of([])  to stop bubble
                catchError((err) => {console.log('error catchError', err); return throwError(err); }) 
            )
            .subscribe(result  => {
                this.validatedReturnOrder = result;
            }, err => {
                console.log('error subscribe', err);
            });
        }

Abp error with message is caught correctly before pipe code runs

:22742/api/services/app/Returns/Validate:1 POST http://localhost:22742/api/services/app/Returns/Validate 500 (Internal Server Error)
abp.js:350 ERROR: 
abp.js:350 {code: -2, message: "No more returns for this order.", details: null, validationErrors: null}

Pipe catchError gets SwaggerException

return-by-order-detail.component.ts:75
error catchError Error: An unexpected server error occurred.
    at new SwaggerException (service-proxies.ts:22907)
    at throwException (service-proxies.ts:22927)
    at MergeMapSubscriber.project (service-proxies.ts:6583)
    at MergeMapSubscriber.push../node_modules/rxjs/_esm5/internal/operators/mergeMap.js.MergeMapSubscriber._tryNext (mergeMap.js:60)
    at MergeMapSubscriber.push../node_modules/rxjs/_esm5/internal/operators/mergeMap.js.MergeMapSubscriber._next (mergeMap.js:50)
    at MergeMapSubscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber.next (Subscriber.js:54)
    at Observable._subscribe (service-proxies.ts:22933)
    at Observable.push../node_modules/rxjs/_esm5/internal/Observable.js.Observable._trySubscribe (Observable.js:42)
    at Observable.push../node_modules/rxjs/_esm5/internal/Observable.js.Observable.subscribe (Observable.js:28)
    at MergeMapOperator.push../node_modules/rxjs/_esm5/internal/operators/mergeMap.js.MergeMapOperator.call (mergeMap.js:28)

Subscribe Error gets SwaggerException

return-by-order-detail.component.ts:80 
error subscribe Error: An unexpected server error occurred.
    at new SwaggerException (service-proxies.ts:22907)
    at throwException (service-proxies.ts:22927)
    at MergeMapSubscriber.project (service-proxies.ts:6583)
    at MergeMapSubscriber.push../node_modules/rxjs/_esm5/internal/operators/mergeMap.js.MergeMapSubscriber._tryNext (mergeMap.js:60)
    at MergeMapSubscriber.push../node_modules/rxjs/_esm5/internal/operators/mergeMap.js.MergeMapSubscriber._next (mergeMap.js:50)
    at MergeMapSubscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber.next (Subscriber.js:54)
    at Observable._subscribe (service-proxies.ts:22933)
    at Observable.push../node_modules/rxjs/_esm5/internal/Observable.js.Observable._trySubscribe (Observable.js:42)
    at Observable.push../node_modules/rxjs/_esm5/internal/Observable.js.Observable.subscribe (Observable.js:28)
    at MergeMapOperator.push../node_modules/rxjs/_esm5/internal/operators/mergeMap.js.MergeMapOperator.call (mergeMap.js:28)

UserFriendlyException returns an Http 500 status code

return content looks like this:

{
  "result": null,
  "targetUrl": null,
  "success": false,
  "error": {
    "code": -2,
    "message": "No more returns for this order.",
    "details": null,
    "validationErrors": null
  },
  "unAuthorizedRequest": false,
  "__abp": true
}

so when trying to catch the error on the subscribe method it just returns a generic swagger error after the framework logs it:

ERROR: 
abp.js:350 {code: -2, message: "No more returns for this order.", details: null, validationErrors: null}

abp.js:350 is:

abp.log.log = function (logObject, logLevel) {
        if (!window.console || !window.console.log) {
            return;
        }

        if (logLevel != undefined && logLevel < abp.log.level) {
            return;
        }

        console.log(logObject); // 350
    };

after that the error pops through the rest:

ERROR Error: An unexpected server error occurred.
    at new SwaggerException (service-proxies.ts:22907)
    at throwException (service-proxies.ts:22927)
    at MergeMapSubscriber.project (service-proxies.ts:6583)
    at MergeMapSubscriber.push../node_modules/rxjs/_esm5/internal/operators/mergeMap.js.MergeMapSubscriber._tryNext (mergeMap.js:60)
    at MergeMapSubscriber.push../node_modules/rxjs/_esm5/internal/operators/mergeMap.js.MergeMapSubscriber._next (mergeMap.js:50)
    at MergeMapSubscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber.next (Subscriber.js:54)
    at Observable._subscribe (service-proxies.ts:22933)
    at Observable.push../node_modules/rxjs/_esm5/internal/Observable.js.Observable._trySubscribe (Observable.js:42)
    at Observable.push../node_modules/rxjs/_esm5/internal/Observable.js.Observable.subscribe (Observable.js:28)
    at MergeMapOperator.push../node_modules/rxjs/_esm5/internal/operators/mergeMap.js.MergeMapOperator.call (mergeMap.js:28)

and this SwaggerException is what the subscribe(err) method is handling.

Question

Hello,

When trying to add actions after user input to backend exceptions, I am having trouble passing the error message as it gets converted to a standard swagger exception

Backend: throw new UserFriendlyException("Order not found");

Angular:

getOrder(event?:LazyLoadEvent){
            this.orderLoading = true;
            this._returnAppService.getOrder(this.orderText)
            .pipe(finalize(()=> {this.orderLoading = false}))
            .subscribe(result=> {
                this.orderDetails = result;                
            },err=> {
                console.log(err);
                debugger;
                abp.message.error(err.message).then(()=> {
                    this.orderText = "";
                    this.orderTextField.nativeElement.focus();
                    //do more custom stuff
                });
            })
            
        }

the err object is a standard SwaggerException "an internal error has ocurred" but abp.js manages to catch the proper message.

Any ideas on how to properly create custom alerts with callbacks that will pass the error message?

Hi, would it be possible to pass the context without being disposed to a view?

Using DevExpress GridView and their sorting/grouping functionality depends on such IQueryable such example can be found here: <a class="postlink" href="https://www.devexpress.com/Support/Center/Example/Details/E3252">https://www.devexpress.com/Support/Cent ... ails/E3252</a>

on asp.net zero im using this:

public ActionResult AdvancedCustomBindingPartial()
        {
 return PartialView("LocationsTablePartial", _locationMasterRepository.GetAll());
}

I've also done a linq query from the service layer with almost the same results:

using (var unitOfWork = UnitOfWorkManager.Begin())
            {
                var query = _locationAppService.BuildLocationQuery();

                viewModel.ProcessCustomBinding(
                    query.GetDataRowCountAdvanced,
                    query.GetDataAdvanced,
                    query.GetSummaryValuesAdvanced,
                    query.GetGroupingInfoAdvanced,
                    query.GetUniqueHeaderFilterValuesAdvanced
                );
            unitOfWork.Complete();
            return PartialView("LocationsTablePartial", viewModel);
            }

and the exception in the view that follows: '((System.Data.Entity.DbSet<Abp.Location.LocationMaster>)Model).Local' threw an exception of type 'System.InvalidOperationException' "The operation cannot be completed because the DbContext has been disposed."

" at System.Data.Entity.Internal.LazyInternalContext.InitializeContext()\r\n at System.Data.Entity.Internal.Linq.InternalQuery1.GetEnumerator()\r\n at System.Data.Entity.Internal.Linq.InternalSet1.GetEnumerator()\r\n at System.Data.Entity.Infrastructure.DbQuery1.System.Collections.Generic.IEnumerable<TResult>.GetEnumerator()\r\n at System.Linq.SystemCore_EnumerableDebugView1.get_Items()"

Any ideas?

Showing 1 to 10 of 15 entries