Base solution for your next web application

Activities of "morindo"

Hi,

I'm building a console app that will use my application services, core services and repositories to insert large amount of data into the database and Azure table storage. I would like to call the services directly, like a client/server app, and I don't want to do remote Web Api calls. I've looked at these samples, AbpWpfDemo and AbpEfConsoleApp but none of these are using authentication/authorization.

I would like to impersonate the host admin. I can't figure out how to do it.

Thank you,

Hi,

I'm trying to debug Abp.* sources (Nuget packages) and it does not work. I can't get the source, the original location is still D:\Halil\GitHub\aspnetboilerplate\src\Abp\AbpBootstrapper.cs.

I've properly configured VS 2015 using:

Debugging <a class="postlink" href="http://www.aspnetboilerplate.com/Pages/Documents/Debugging">http://www.aspnetboilerplate.com/Pages/ ... /Debugging</a>

Thank you,

Ok, I found an example of an IAbpSession implementation for a console app.

Please see: [https://github.com/aspnetzero/aspnet-zero-samples/tree/master/PhoneBook/src/Acme.PhoneBook.ConsoleApp])

Hi,

I'm trying to create an attribute class and I would like to get the ILogger but I'm getting a null reference, how can I inject the ILogger into an attribute class?

I've tried to register the class with an ITransientDependency and also in the PreInitialize() method:

IocManager.Register<SkipConcurrentExecutionAttribute>(DependencyLifeStyle.Transient);

Thank you,

/// <summary>
    /// Attribute to skip a job execution if the same job is already running.
    /// Mostly taken from: http://discuss.hangfire.io/t/job-reentrancy-avoidance-proposal/607
    /// </summary>
    public class SkipConcurrentExecutionAttribute : JobFilterAttribute, IServerFilter
    {
        public ILogger Logger { get; set; }

        private readonly int _timeoutInSeconds = 1;

        public SkipConcurrentExecutionAttribute()
        {
            Logger = NullLogger.Instance;
        }

        public SkipConcurrentExecutionAttribute(int timeoutInSeconds) : this()
        {
            if (timeoutInSeconds < 0) throw new ArgumentException("Timeout argument value should be greater that zero.");

            _timeoutInSeconds = timeoutInSeconds;
        }


        public void OnPerforming(PerformingContext filterContext)
        {
            var resource = String.Format(
                                 "{0}.{1}",
                                filterContext.Job.Type.FullName,
                                filterContext.Job.Method.Name);

            var timeout = TimeSpan.FromSeconds(_timeoutInSeconds);

            try
            {
                var distributedLock = filterContext.Connection.AcquireDistributedLock(resource, timeout);
                filterContext.Items["DistributedLock"] = distributedLock;
            }
            catch (Exception)
            {
                filterContext.Canceled = true;
                Logger.WarnFormat("Cancelling run for {0} job, id: {1} ", resource, filterContext.JobId); // Not logging anything...
            }
        }

        public void OnPerformed(PerformedContext filterContext)
        {
            if (!filterContext.Items.ContainsKey("DistributedLock"))
            {
                throw new InvalidOperationException("Can not release a distributed lock: it was not acquired.");
            }

            var distributedLock = (IDisposable)filterContext.Items["DistributedLock"];
            distributedLock.Dispose();
        }
    }

Okay, I found a way.

I created this SkipConcurrentExecutionAttribute class for Hangfire in order to skip concurrent task execution. Since Hangfire already supports logging with Log4Net, I've used the LogProvider.GetCurrentClassLogger() method to get the logger.

See Hangfire documentation - Configuring logging [http://docs.hangfire.io/en/latest/configuration/configuring-logging.html])

/// <summary>
    /// Attribute to skip a job execution if the same job is already running.
    /// Mostly taken from: http://discuss.hangfire.io/t/job-reentrancy-avoidance-proposal/607
    /// </summary>
    public class SkipConcurrentExecutionAttribute : JobFilterAttribute, IServerFilter
    {
        private static readonly ILog Logger = LogProvider.GetCurrentClassLogger();

        private readonly int _timeoutInSeconds = 1;

        public SkipConcurrentExecutionAttribute()
        {
        }

        public SkipConcurrentExecutionAttribute(int timeoutInSeconds) : this()
        {
            if (timeoutInSeconds < 0) throw new ArgumentException("Timeout argument value should be greater that zero.");

            _timeoutInSeconds = timeoutInSeconds;
        }


        public void OnPerforming(PerformingContext filterContext)
        {
            var resource = String.Format(
                                 "{0}.{1}",
                                filterContext.Job.Type.FullName,
                                filterContext.Job.Method.Name);

            var timeout = TimeSpan.FromSeconds(_timeoutInSeconds);

            try
            {
                var distributedLock = filterContext.Connection.AcquireDistributedLock(resource, timeout);
                filterContext.Items["DistributedLock"] = distributedLock;
            }
            catch (Exception)
            {
                filterContext.Canceled = true;
                Logger.WarnFormat("Cancelling run for {0} job, id: {1} ", resource, filterContext.JobId);
            }
        }

        public void OnPerformed(PerformedContext filterContext)
        {
            if (!filterContext.Items.ContainsKey("DistributedLock"))
            {
                throw new InvalidOperationException("Can not release a distributed lock: it was not acquired.");
            }

            var distributedLock = (IDisposable)filterContext.Items["DistributedLock"];
            distributedLock.Dispose();
        }
    }

I'm having the same issue. Should optional parameters accept null value?

Thanks,

Thanks @maliming for the quick reply. So, for Swashbuckle.AspNetCore nuget package the version is 5.0.0-rc4. Just so you know, it's a new solution, started from ASP.NET Zero (Angular) version 8.1.0 and I didn't update any nuget or npm packages.


Here is my service.config.nswag configuration file.

{
  "runtime": "Default",
  "defaultVariables": null,
  "documentGenerator": {
    "fromDocument": {
      "url": "http://localhost:22742/swagger/v1/swagger.json",
      "output": null
    }
  },
  "codeGenerators": {
    "openApiToTypeScriptClient": {
      "className": "{controller}ServiceProxy",
      "moduleName": "",
      "namespace": "",
      "typeScriptVersion": 2.7,
      "template": "Angular",
      "promiseType": "Promise",
      "httpClass": "HttpClient",
      "useSingletonProvider": false,
      "injectionTokenType": "InjectionToken",
      "rxJsVersion": 6.0,
      "dateTimeType": "MomentJS",
      "nullValue": "Undefined",
      "generateClientClasses": true,
      "generateClientInterfaces": false,
      "generateOptionalParameters": false,
      "exportTypes": true,
      "wrapDtoExceptions": false,
      "exceptionClass": "ApiException",
      "clientBaseClass": null,
      "wrapResponses": false,
      "wrapResponseMethods": [],
      "generateResponseClasses": true,
      "responseClass": "SwaggerResponse",
      "protectedMethods": [],
      "configurationClass": null,
      "useTransformOptionsMethod": false,
      "useTransformResultMethod": false,
      "generateDtoTypes": true,
      "operationGenerationMode": "MultipleClientsFromPathSegments",
      "markOptionalProperties": false,
      "generateCloneMethod": false,
      "typeStyle": "Class",
      "classTypes": [],
      "extendedClasses": [],
      "extensionCode": "service.extensions.ts",
      "generateDefaultValues": true,
      "excludedTypeNames": [],
      "excludedParameterNames": [],
      "handleReferences": false,
      "generateConstructorInterface": true,
      "convertConstructorInterfaceData": false,
      "importRequiredTypes": true,
      "useGetBaseUrlMethod": false,
      "baseUrlTokenName": "API_BASE_URL",
      "queryNullValue": "",
      "inlineNamedDictionaries": false,
      "inlineNamedAny": false,
      "templateDirectory": null,
      "typeNameGeneratorType": null,
      "propertyNameGeneratorType": null,
      "enumNameGeneratorType": null,
      "serviceHost": null,
      "serviceSchemes": null,
      "output": "../src/shared/service-proxies/service-proxies.ts"
    },
    "openApiToCSharpClient": {
      "clientBaseClass": null,
      "configurationClass": null,
      "generateClientClasses": true,
      "generateClientInterfaces": false,
      "injectHttpClient": false,
      "disposeHttpClient": true,
      "protectedMethods": [],
      "generateExceptionClasses": true,
      "exceptionClass": "SwaggerException",
      "wrapDtoExceptions": true,
      "useHttpClientCreationMethod": false,
      "httpClientType": "System.Net.Http.HttpClient",
      "useHttpRequestMessageCreationMethod": false,
      "useBaseUrl": true,
      "generateBaseUrlProperty": true,
      "generateSyncMethods": false,
      "exposeJsonSerializerSettings": false,
      "clientClassAccessModifier": "public",
      "typeAccessModifier": "public",
      "generateContractsOutput": false,
      "contractsNamespace": null,
      "contractsOutputFilePath": null,
      "parameterDateTimeFormat": "s",
      "generateUpdateJsonSerializerSettingsMethod": true,
      "serializeTypeInformation": false,
      "queryNullValue": "",
      "className": "{controller}Client",
      "operationGenerationMode": "MultipleClientsFromOperationId",
      "additionalNamespaceUsages": [],
      "additionalContractNamespaceUsages": [],
      "generateOptionalParameters": false,
      "generateJsonMethods": true,
      "enforceFlagEnums": false,
      "parameterArrayType": "System.Collections.Generic.IEnumerable",
      "parameterDictionaryType": "System.Collections.Generic.IDictionary",
      "responseArrayType": "System.Collections.ObjectModel.ObservableCollection",
      "responseDictionaryType": "System.Collections.Generic.Dictionary",
      "wrapResponses": false,
      "wrapResponseMethods": [],
      "generateResponseClasses": true,
      "responseClass": "SwaggerResponse",
      "namespace": "MyNamespace",
      "requiredPropertiesMustBeDefined": true,
      "dateType": "System.DateTime",
      "jsonConverters": null,
      "anyType": "object",
      "dateTimeType": "System.DateTime",
      "timeType": "System.TimeSpan",
      "timeSpanType": "System.TimeSpan",
      "arrayType": "System.Collections.ObjectModel.ObservableCollection",
      "arrayInstanceType": "System.Collections.ObjectModel.Collection",
      "dictionaryType": "System.Collections.Generic.Dictionary",
      "dictionaryInstanceType": "System.Collections.Generic.Dictionary",
      "arrayBaseType": "System.Collections.ObjectModel.ObservableCollection",
      "dictionaryBaseType": "System.Collections.Generic.Dictionary",
      "classStyle": "Inpc",
      "generateDefaultValues": true,
      "generateDataAnnotations": true,
      "excludedTypeNames": [],
      "excludedParameterNames": [],
      "handleReferences": false,
      "generateImmutableArrayProperties": false,
      "generateImmutableDictionaryProperties": false,
      "jsonSerializerSettingsTransformationMethod": null,
      "inlineNamedArrays": false,
      "inlineNamedDictionaries": false,
      "inlineNamedTuples": true,
      "inlineNamedAny": false,
      "generateDtoTypes": true,
      "generateOptionalPropertiesAsNullable": false,
      "templateDirectory": null,
      "typeNameGeneratorType": null,
      "propertyNameGeneratorType": null,
      "enumNameGeneratorType": null,
      "serviceHost": null,
      "serviceSchemes": null,
      "output": null
    },
    "openApiToCSharpController": {
      "controllerBaseClass": null,
      "controllerStyle": "Partial",
      "controllerTarget": "AspNet",
      "useCancellationToken": false,
      "useActionResultType": false,
      "generateModelValidationAttributes": false,
      "routeNamingStrategy": "None",
      "className": "{controller}",
      "operationGenerationMode": "MultipleClientsFromOperationId",
      "additionalNamespaceUsages": [
        "System.Web.Http"
      ],
      "additionalContractNamespaceUsages": [],
      "generateOptionalParameters": false,
      "generateJsonMethods": true,
      "enforceFlagEnums": false,
      "parameterArrayType": "System.Collections.Generic.IEnumerable",
      "parameterDictionaryType": "System.Collections.Generic.IDictionary",
      "responseArrayType": "System.Collections.ObjectModel.ObservableCollection",
      "responseDictionaryType": "System.Collections.Generic.Dictionary",
      "wrapResponses": false,
      "wrapResponseMethods": [],
      "generateResponseClasses": true,
      "responseClass": "SwaggerResponse",
      "namespace": "MyNamespace",
      "requiredPropertiesMustBeDefined": true,
      "dateType": "System.DateTime",
      "jsonConverters": null,
      "anyType": "object",
      "dateTimeType": "System.DateTime",
      "timeType": "System.TimeSpan",
      "timeSpanType": "System.TimeSpan",
      "arrayType": "System.Collections.Generic.IEnumerable",
      "arrayInstanceType": "System.Collections.ObjectModel.Collection",
      "dictionaryType": "System.Collections.Generic.Dictionary",
      "dictionaryInstanceType": "System.Collections.Generic.Dictionary",
      "arrayBaseType": "System.Collections.ObjectModel.ObservableCollection",
      "dictionaryBaseType": "System.Collections.Generic.Dictionary",
      "classStyle": "Inpc",
      "generateDefaultValues": true,
      "generateDataAnnotations": true,
      "excludedTypeNames": [],
      "excludedParameterNames": [],
      "handleReferences": false,
      "generateImmutableArrayProperties": false,
      "generateImmutableDictionaryProperties": false,
      "jsonSerializerSettingsTransformationMethod": null,
      "inlineNamedArrays": false,
      "inlineNamedDictionaries": false,
      "inlineNamedTuples": true,
      "inlineNamedAny": false,
      "generateDtoTypes": true,
      "generateOptionalPropertiesAsNullable": false,
      "templateDirectory": null,
      "typeNameGeneratorType": null,
      "propertyNameGeneratorType": null,
      "enumNameGeneratorType": null,
      "serviceHost": null,
      "serviceSchemes": null,
      "output": null
    }
  }
}

When I run refresh.bat, I get the following result.

R:\Dev\Repos\BakeSimple\angular\nswag>"..\node_modules\.bin\nswag" run
NSwag NPM CLI
NSwag command line tool for .NET Core NetCore21, toolchain v13.0.6.0 (NJsonSchema v10.0.23.0 (Newtonsoft.Json v11.0.0.0))
Visit http://NSwag.org for more information.
NSwag bin directory: R:\Dev\Repos\BakeSimple\angular\node_modules\nswag\bin\binaries\NetCore21

Executing file 'R:\Dev\Repos\BakeSimple\angular\nswag\service.config.nswag' with variables ''...
Done.

Duration: 00:00:05.3494464

Finally, here is part of my service-proxies.ts generated file.

/**
     * @param filter (optional) 
     * @param nameFilter (optional) 
     * @param sorting (optional) 
     * @param skipCount (optional) 
     * @param maxResultCount (optional) 
     * @return Success
     */
    getAll(filter: string | undefined, nameFilter: string | undefined, sorting: string | undefined, skipCount: number | undefined, maxResultCount: number | undefined): Observable<PagedResultDtoOfGetProductCategoryForViewDto> {
        let url_ = this.baseUrl + "/api/services/app/ProductCategories/GetAll?";
        if (filter === null)
            throw new Error("The parameter 'filter' cannot be null.");
        else if (filter !== undefined)
            url_ += "Filter=" + encodeURIComponent("" + filter) + "&"; 
        if (nameFilter === null)
            throw new Error("The parameter 'nameFilter' cannot be null.");
        else if (nameFilter !== undefined)
            url_ += "NameFilter=" + encodeURIComponent("" + nameFilter) + "&"; 
        if (sorting === null)
            throw new Error("The parameter 'sorting' cannot be null.");
        else if (sorting !== undefined)
            url_ += "Sorting=" + encodeURIComponent("" + sorting) + "&"; 
        if (skipCount === null)
            throw new Error("The parameter 'skipCount' cannot be null.");
        else if (skipCount !== undefined)
            url_ += "SkipCount=" + encodeURIComponent("" + skipCount) + "&"; 
        if (maxResultCount === null)
            throw new Error("The parameter 'maxResultCount' cannot be null.");
        else if (maxResultCount !== undefined)
            url_ += "MaxResultCount=" + encodeURIComponent("" + maxResultCount) + "&"; 
        url_ = url_.replace(/[?&]$/, "");

        let options_ : any = {
            observe: "response",
            responseType: "blob",
            headers: new HttpHeaders({
                "Accept": "text/plain"
            })
        };

        return this.http.request("get", url_, options_).pipe(_observableMergeMap((response_ : any) => {
            return this.processGetAll(response_);
        })).pipe(_observableCatch((response_: any) => {
            if (response_ instanceof HttpResponseBase) {
                try {
                    return this.processGetAll(<any>response_);
                } catch (e) {
                    return <Observable<PagedResultDtoOfGetProductCategoryForViewDto>><any>_observableThrow(e);
                }
            } else
                return <Observable<PagedResultDtoOfGetProductCategoryForViewDto>><any>_observableThrow(response_);
        }));
    }

    protected processGetAll(response: HttpResponseBase): Observable<PagedResultDtoOfGetProductCategoryForViewDto> {
        const status = response.status;
        const responseBlob = 
            response instanceof HttpResponse ? response.body : 
            (<any>response).error instanceof Blob ? (<any>response).error : undefined;

        let _headers: any = {}; if (response.headers) { for (let key of response.headers.keys()) { _headers[key] = response.headers.get(key); }};
        if (status === 200) {
            return blobToText(responseBlob).pipe(_observableMergeMap(_responseText => {
            let result200: any = null;
            let resultData200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver);
            result200 = PagedResultDtoOfGetProductCategoryForViewDto.fromJS(resultData200);
            return _observableOf(result200);
            }));
        } else if (status !== 200 && status !== 204) {
            return blobToText(responseBlob).pipe(_observableMergeMap(_responseText => {
            return throwException("An unexpected server error occurred.", status, _responseText, _headers);
            }));
        }
        return _observableOf<PagedResultDtoOfGetProductCategoryForViewDto>(<any>null);
    }
    ```

Thank you very much @maliming, it just works!

/**
 * @param filter (optional) 
 * @param nameFilter (optional) 
 * @param sorting (optional) 
 * @param skipCount (optional) 
 * @param maxResultCount (optional) 
 * @return Success
 */
getAll(filter: string | null | undefined, nameFilter: string | null | undefined, sorting: string | null | undefined, skipCount: number | undefined, maxResultCount: number | undefined): Observable&lt;PagedResultDtoOfGetProductCategoryForViewDto&gt; {
    let url_ = this.baseUrl + "/api/services/app/ProductCategories/GetAll?";
    if (filter !== undefined)
        url_ += "Filter=" + encodeURIComponent("" + filter) + "&"; 
    if (nameFilter !== undefined)
        url_ += "NameFilter=" + encodeURIComponent("" + nameFilter) + "&"; 
    if (sorting !== undefined)
        url_ += "Sorting=" + encodeURIComponent("" + sorting) + "&"; 
    if (skipCount === null)
        throw new Error("The parameter 'skipCount' cannot be null.");
    else if (skipCount !== undefined)
        url_ += "SkipCount=" + encodeURIComponent("" + skipCount) + "&"; 
    if (maxResultCount === null)
        throw new Error("The parameter 'maxResultCount' cannot be null.");
    else if (maxResultCount !== undefined)
        url_ += "MaxResultCount=" + encodeURIComponent("" + maxResultCount) + "&"; 
    url_ = url_.replace(/[?&]$/, "");

    let options_ : any = {
        observe: "response",
        responseType: "blob",			
        headers: new HttpHeaders({
            "Accept": "text/plain"
        })
    };

So adding SwaggerNullableParameterFilter class is wokring, it remove the null check.

Now, on the nswag (refresh.bat) generation process, how can we opt out null parameter in query string or replace null value by empty string so encodeURIComponent does not encode null to "null". Is there a way to do this? I've been searching this morning and can't find anything to fix it.

Example:

getAll(filter: string | null | undefined, productCategoryIdFilter: string | null | undefined, taxRateIdFilter: string | null | undefined, sorting: string | null | undefined, skipCount: number | undefined, maxResultCount: number | undefined): Observable<PagedResultDtoOfGetProductForViewDto> { let url_ = this.baseUrl + "/api/services/app/Products/GetAll?"; if (filter !== undefined) url_ += "Filter=" + encodeURIComponent("" + filter) + "&"; if (productCategoryIdFilter !== undefined) url_ += "ProductCategoryIdFilter=" + encodeURIComponent("" + productCategoryIdFilter) + "&"; if (taxRateIdFilter !== undefined) url_ += "TaxRateIdFilter=" + encodeURIComponent("" + taxRateIdFilter) + "&"; if (sorting !== undefined) url_ += "Sorting=" + encodeURIComponent("" + sorting) + "&"; if (skipCount === null) throw new Error("The parameter 'skipCount' cannot be null."); else if (skipCount !== undefined) url_ += "SkipCount=" + encodeURIComponent("" + skipCount) + "&"; if (maxResultCount === null) throw new Error("The parameter 'maxResultCount' cannot be null."); else if (maxResultCount !== undefined) url_ += "MaxResultCount=" + encodeURIComponent("" + maxResultCount) + "&"; url_ = url_.replace(/[?&]$/, "");

The line:

if (productCategoryIdFilter !== undefined) url_ += "ProductCategoryIdFilter=" + encodeURIComponent("" + productCategoryIdFilter) + "&";

Should be:

if (productCategoryIdFilter !== undefined) url_ += "ProductCategoryIdFilter=" + encodeURIComponent(productCategoryIdFilter ? "" + productCategoryIdFilter : "") + "&";

Thank you,

Thank you very much maliming. Cheers!

Showing 1 to 10 of 13 entries