From 92e07790cc315162c1855cd2ac5d4831d8ac6bcf Mon Sep 17 00:00:00 2001 From: Polianin Nikita Date: Sun, 23 Nov 2025 13:24:48 +0300 Subject: [PATCH] build: add support .net 10 --- Directory.Build.props | 8 +- Dockerfile | 22 +-- .../Core/Startup/LoggerConfiguration.cs | Bin 5047 -> 10342 bytes .../Core/Startup/SwaggerConfiguration.cs | Bin 2942 -> 5080 bytes .../ActionResultSchemaFilter.cs | 81 ----------- .../SwaggerOptions/ConfigureSwaggerOptions.cs | Bin 1631 -> 3316 bytes .../SwaggerOptions/DefaultValues.cs | 51 ------- .../SwaggerOptions/EnumSchemaFilter.cs | 28 ---- .../SwaggerOptions/ExampleFilter.cs | 16 --- .../SwaggerOptions/TagSchemeFilter.cs | 40 ------ Endpoint/Endpoint.csproj | 68 ++++----- Endpoint/Program.cs | Bin 8147 -> 16702 bytes Endpoint/Properties/launchSettings.json | Bin 1407 -> 1806 bytes .../Resources/SharedResources.Designer.cs | 90 ++++++++++++ Endpoint/Resources/SharedResources.resx | 129 ++++++++++++++++++ Endpoint/Resources/SharedResources.ru-RU.resx | 129 ++++++++++++++++++ Security/Security.csproj | 2 - SqlData/Application/Application.csproj | 14 +- SqlData/Persistence/DependencyInjection.cs | Bin 5897 -> 12096 bytes SqlData/Persistence/Persistence.csproj | 5 +- 20 files changed, 401 insertions(+), 282 deletions(-) delete mode 100644 Endpoint/Configuration/SwaggerOptions/ActionResultSchemaFilter.cs delete mode 100644 Endpoint/Configuration/SwaggerOptions/DefaultValues.cs delete mode 100644 Endpoint/Configuration/SwaggerOptions/EnumSchemaFilter.cs delete mode 100644 Endpoint/Configuration/SwaggerOptions/ExampleFilter.cs delete mode 100644 Endpoint/Configuration/SwaggerOptions/TagSchemeFilter.cs create mode 100644 Endpoint/Resources/SharedResources.Designer.cs create mode 100644 Endpoint/Resources/SharedResources.resx create mode 100644 Endpoint/Resources/SharedResources.ru-RU.resx diff --git a/Directory.Build.props b/Directory.Build.props index 899da35..bedb16d 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,14 +1,14 @@  - net8.0 + net10.0 disable enable true Winsomnia - 1.1.0 - 1.1.3.0 - 1.1.3.0 + 1.2.0 + 1.2.0.0 + 1.2.0.0 \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 0661923..ca0f610 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base +FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS base LABEL company="Winsomnia" LABEL maintainer.name="Wesser" maintainer.email="support@winsomnia.net" WORKDIR /app @@ -7,7 +7,7 @@ RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/* HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \ CMD curl --fail http://localhost:8080/health || exit 1 -FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build +FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build WORKDIR /src COPY . . @@ -15,15 +15,19 @@ ARG NUGET_USERNAME ARG NUGET_PASSWORD ARG NUGET_ADDRESS -ENV NUGET_USERNAME=$NUGET_USERNAME -ENV NUGET_PASSWORD=$NUGET_PASSWORD -ENV NUGET_ADDRESS=$NUGET_ADDRESS +RUN dotnet nuget add source ${NUGET_ADDRESS} \ + --name Winsomnia \ + --username ${NUGET_USERNAME} \ + --password ${NUGET_PASSWORD} \ + --store-password-in-clear-text -RUN dotnet nuget add source --name="Winsomnia" --username ${NUGET_USERNAME} --store-password-in-clear-text --password ${NUGET_PASSWORD} ${NUGET_ADDRESS} RUN dotnet restore ./Backend.sln -WORKDIR /app -WORKDIR /src -RUN dotnet publish ./Endpoint/Endpoint.csproj -c Release --self-contained false -p:PublishSingleFile=false -o /app + +RUN dotnet publish Endpoint/Endpoint.csproj \ + -c Release \ + --self-contained false \ + -p:PublishSingleFile=false \ + -o /app FROM base AS final WORKDIR /app diff --git a/Endpoint/Configuration/Core/Startup/LoggerConfiguration.cs b/Endpoint/Configuration/Core/Startup/LoggerConfiguration.cs index aadb912f475529a48f4168d91c328b3b5639e6e6..e56b95c16451e631e46f421c3f1e4926027d1981 100644 GIT binary patch literal 10342 zcmdU#ZEw?76vyxDN&60_FQ!yO9^14xWq`U;Mkb&L7`#B!6xz^+wM~|!K-cxFZ~Oo5 z@u_3ScI>uDLs4;JU!Qv(|L5WI&%fa$%)%%fhy9R*$NIJ#reUmmqeG;C8 zp?+=Y?o{8>@RQyfg~PC?U(;|qd>Ou2NohNL6pf+wV#jg3rjh2c_8N(U6VV!IjXk{z z)rV0AC?Q!jB_tU{2`5^YhHb6gldR+T7P2Gnkv{O6hUZb%_j$k&utv%M-D%r}bA4m^}(Vo+m>+zkVXkWLBYj~o& zyEQzXiaIhJW%fAKuEV%G_o1I7-*_UnsgiV&%6+XGNQ1}HBeZ#^TH?jG`e7%djISSy z!jX0*HsF1jMNd1QsqM_H`6ul6Lzfp~_qdMXE*J&M%V z3;Y$ib*|AmnwrWkiFPu(7U`tnSM5Js;;bjV5#JssH$~z1z`u6C3YpgR^iH^2;LLfc z=Fp$Mk5*0OeMB188OUnb-F*VezPIz_v0TMV8u0#k_%U9qY2FRJupaIyg3K?7<+(nF zj_&);WBFRI2mGhJy8IhVW1o?{;zWOsv^O|&C~ofS`bKy6BY#(=wiD@2rPEQw&|X-p z$Y^WPwx)+1@fNx2M_c4*WjIsx!?KkA+p>t^(19d;AZ~~U+t2LmR>damWPTN8;=LE5 z=H5V#1`B(ws5pmX>3bgId@gF>>LlU@)Hga&S_`j*9=YZ=MEU!09)6Qg@Z?3bIT#6+ zvCl@t2|VJlq&Uq!iE!nio{?!cw0f4&IMXWLp6PAkWkYm!o5p*9#q)_#3R%iyx&SlFs+IHz&>o;Uw zwC2?M`u#*YB+KvUeop-|9D~ze>5~X)MxthQ1Cf0iIsd4;>_2O?f1N(oSJ>HQ^=lOm zTahd5H>}|Cax&kJQQQVu>XAJSWz2DJ>xMSO=LhNEywB^rU!-wj^nw1(YeKRin0T`j z3bpn3Hu`W&`L%lt-ss4E_nn?ZECqAE*58`^_+6&WwN85Ls^_MRndk9twj(zZ=@$Kc zc?5AVRUW4*+K_zD8dp$33>J{bwOPKNuZ)Q6#UnDtj!=;rj~q*urdt5%PM7-3=4|1z z7>->RUejh|-G=-w+ueUVhu+Wcj{hMVCx_o>k~BN!|6lRdrd9K5ckv>QvkH zmUYuopPQIgS9hSVl+~DJ*!p();nQ*dSU#|;NFV~6s(}9&*HjK*&F87}&B*&f7RO+Z z&H0Gp&&?7p3$^|z{BN+N~zn&G9C|aOrC5; z{XtwzRTaPuJ+M{HP}b7QUpLQ@HYiT?p#FF>e`?Wy`7wGIb3Z_3D#i>Lxp3=*u!zk#1^V z>`V^E*4U3)3!cgQ^dGj`CN>rm?uV&*l0};K4js@)@B3+9Q^s68GwfwKq3G+WVue-9 zF@x_G_qVtx%DJlFxGD#B7BE$1YSr6ZT;((WTvJrCe@YUYVp1P*W@x9LRN2dP(C%0$ zfIOCam}z`!dEk?CN;vOJ_jV$KKQKS7mdz}Nr{!&w{Esun5WZ57MDIPJ2v?)CM!nPpxLa_x3M3FU#HEXf-&( z`T0SXZJTuFocVPcb>`=tO*Q#Tt(+>)b0RuyaT-#+Ls8?2dT;vP@4^q!{z>>-AG1Od zZp3HD@+2mEU8Le{p-Glvf6;|9lf-HnzRf(i3pLl#Dt`NloVU`vPq=NiahaXqzezLs z{B;#lc8^bH0Aw=iVWu?Y|2a|2`yRbi)6FZ1+v*5w6UlCab`kBXS94|m%V!=d>>?6- z4{y1&n)79B@VC+H|^`WQ%XE%FtyAx^cW*V|C+n cbkH5S0~gT>eEOC4DeYO4d&0 zQx!m1O5<)Bs@*ZgSJKnMqism>$qHh-JE;^tlc5FOeynsPEEz$nCc>}a*2Y4FPs0#= z@`T}UAx2I7-GRBpsT7Nt9N|~!`J0QYR|f~Nh`=B)U_d(DQ#U$`(98;L(*$=W={%G^ zGZq8kGd~o@u=i@Q0PRHRU~|B5xzZODnj+Y26a?ecSQQn{@a$3==7=mS@qPxEgA%X? zo9dX=B={c&N+{3Iqj1RnJY@K}VoskOpJY%3Qo+%;mC$TK&J+?f&$Nng8=6OEcAfiCOAEJ(JYZA^UQ2({PNgLUd3l zuC)1D*d;Q8{uLCauw83Sf*Sz{2kP6G#o06O6-dUebj;*3Fd|9#~P;-We62 z<+Tp9*FSW^N!YZy9NsBN!h0k4q8ohgo=Yr{>?hXapHatN=Xrbdb+a(b=kBvL7I9?8 z1*V=}iEzMf+z0$r5MfBga&6m;{|@R5`Beh(Erbw()$6hiwpoF!`VKf34NERHQSw*6 zjo3{NM;%XP`E2TixwN;Pn)IgFu064Yu-lwO1Q43Z#Cv(UEl2EN9oLD%-E2&jXpEGa_Xx0#mA!|~-#&GOJ zi4C2O*|z<)Z5Bm`Gc6RiU3N6W`e0dT+3JlSg^n@x+I)Q$`gG<0AmkftsHoo$LLa4e ziSd+vHcS7&LzI?(KYd1{pE#lC`E<T~)>SG|gBcV^bTTkiS;i^_fQQJ}CVqn|n`%6?0*LT74wqpx5u$N-|NG zGNvfYjbV3`BseK&_Lnm+j;LKTZ-=BvlAN7Y>K7v~zM)aq6J{OzteSLV9N@k&-CB(k z|3!c`Vua;qh1T+Msx@+9$nh}_D;R(*y>D|#V#&Rvo0*e``8Ca}21kCKnq4@&Ua=bk zP@LH44By(1=IIfZbc+b3MmO+Rit{2r2Z2{bLoUc=_^p~{BbJA;d6t?t5Ge~6*LV}r zIBV7pLwdyd{fZYtNg*`ce_RzQ;sh=6Af&~5Pm{G<__jMmxBc41r7#j5yCAlAbVm1( zvdju*1o9ItyeHDkQ);#V27%_J0w zfnadNk8o{SWO@xwl&av}C>!%p2XAR@LYamRIAoAR;D<+trsOEsDtbawacw(>ArC(( z&$HX8p%O5I1+^y3?p(>u=@Hf~`>r|Fa(ls+N+U(m0eQlw53wRX4LyJyhQB%4GVENoa_#xTDe zRzD#WF{F?NyWbUdfvtt96YnTtk)~zOpP1!u?D?k0KMWLM2Oco*BU~l y^)&L#U*Z_N2RncHJltI&+Jo6DSkHrRq-W!h?<-VP*&El;+*Q@z+F(|7we9~z^8c~` diff --git a/Endpoint/Configuration/Core/Startup/SwaggerConfiguration.cs b/Endpoint/Configuration/Core/Startup/SwaggerConfiguration.cs index ae6f3f95cd106495731f3a54a23d6165a7d95067..7cb2f14b20e8c852aa86bec4bfc497de6eb2da53 100644 GIT binary patch literal 5080 zcmd5=+fLg+5S`~r{RbCS!jX{q04Nd=+R__{OIxYxg9!oL2FH!Vtth|V_MBZ$?6r+q zS{^DZalE^pJ#*&l>}-DhmJ7)xkyK74kahgdB$AIZl!<8{qsR6}=*{qZORjMr$rvLz zYDJ#P6UWMXj2fV43=3m9ktr-%%OCK@R5puuBiX=v32Yrdz!K-5VthKsm&1M^EtzSh ztrYX$$TsfZ@HD{q1aqdISlegVfqk`;ds^ZaT%vb?Uw0w#vzj702_k<1i}Bn$&T)n3Q(TA+k;!a;_kGy2K`i7Ah{&Ss?rHN4uSE1XtQCR60x+2HShc^{H=*;!I z>rd%B^Au-HVC%-@GpM&Hi3AaBvj zY#(3_`V`0;`6LJCd5rACj1m~`$`Rypi1l!cp3q^DWAv>a81_T>q3~HTts{0sLlq?Q zv*N$6#REj0yM?vb6+azGW~aEaPEKdido)$<0pAaJYO^V0&b1MORmS|nsDLf>p?#HV zg#C1;tCo5{!H0M5?aI=_wNDRROU+f~!E zp*U84*HGOEEj@GjuvpK)%x2u7FHDa5Z0u>xWflH-2v-c}T__)$DO-E?!SmScVgvB~ z|FU*JTFcfzPax`n&3?tnRRAywP7*yK(5b9K;V;}DU5tlG0J-{`rNr->Vr5qW-MUBmtKIr7;pe4C($)zb)E zlA}mi6;Gi!o;9?FogsViY_W___1v~xQ)VCPo}fO8it)^u?W;-o()~AU#EeyQJ#Hns zYCO4ysF|epuR?o`S69ax*ie*J-77-9pP0&vbtdav?lg*>Dr>7HxxesC<*M-+*zrf3 z16vm=zx`T~vWgf16S<`Vn(@3fJ50|xT}xd4vsX5DQzLG0`nDEdH4W1Aa_R7ompH}IGBp`X-W z*csg{S;{sK<%=Nl%;DUJ|Ni|?=A_=Ru}k@9uud9{zkHm^*)CPaf;}G;h+7$1*c_ii3OWWI?dSR{L>@Q0oDKY4N)Xq@+#wGt#&1mws&Q^X zkivYX|2T+FwI&UJx+XpKQnZBf>8*2 zeAhT`F?Ai--622qQ1*m_khJI_g;ZuVA68OBSk>K#1+j@7 z-z6#-4vUW0w4}<7xsFs8!*7YA34>|zCccwId#gs6v{P@U|Fd2l*7Mqb0GI0?#~s}ZX~ zB27p2FuS+rSz?E(jW``;h~~&$O~S_DDXnh<9_MeLa>Yw$;r9yM7Qlz^f|p0DK7hjU z$8W$dvK6J`A#(1_70-^dQjw{!PaOAyhC-B$G%3=`rpwx@oUItv7jq16`HE|F;mQ&D z?5V>|lxuv$iD=70;*J}A8#{D$)lbwuyQHpNCf!~_l$ll71KtI-i7$;y_>DDLO5OcX zo%65G=-`-=q$4fjqBj(h^%C%bB#zTuwS3}j!3F1F5O(c7DH4LXCt!zK<2?@ j9_}qp)g9{47s-;9FRe_%_h;`<$c}A_%8b-G3=ZD`9$$R# diff --git a/Endpoint/Configuration/SwaggerOptions/ActionResultSchemaFilter.cs b/Endpoint/Configuration/SwaggerOptions/ActionResultSchemaFilter.cs deleted file mode 100644 index f1584e2..0000000 --- a/Endpoint/Configuration/SwaggerOptions/ActionResultSchemaFilter.cs +++ /dev/null @@ -1,81 +0,0 @@ -using Microsoft.AspNetCore.Mvc; -using Microsoft.OpenApi.Models; -using Swashbuckle.AspNetCore.SwaggerGen; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace Mirea.Api.Endpoint.Configuration.SwaggerOptions; - -public class ActionResultSchemaFilter : IOperationFilter -{ - public void Apply(OpenApiOperation operation, OperationFilterContext context) - { - var returnType = context.MethodInfo.ReturnType; - if (!returnType.IsEquivalentTo(typeof(ActionResult)) && - !returnType.IsEquivalentTo(typeof(ContentResult)) && - !returnType.IsEquivalentTo(typeof(FileStreamResult)) && - !returnType.IsGenericType) - return; - - if (returnType.IsGenericType && - !returnType.GetGenericTypeDefinition().IsEquivalentTo(typeof(ActionResult<>)) && - !returnType.GetGenericTypeDefinition().IsEquivalentTo(typeof(Task<>))) - return; - - var genericType = returnType.IsGenericType ? returnType.GetGenericArguments().FirstOrDefault() : returnType; - if (genericType == null) - return; - - var responseTypeAttributes = context.MethodInfo.GetCustomAttributes(typeof(ProducesResponseTypeAttribute), false) - .Cast() - .Where(attr => attr.StatusCode == 200) - .ToList(); - - var contentType = "application/json"; - - if (context.MethodInfo.GetCustomAttributes(typeof(ProducesAttribute), false) - .FirstOrDefault() is ProducesAttribute producesAttribute) - contentType = producesAttribute.ContentTypes.FirstOrDefault() ?? "application/json"; - - if (responseTypeAttributes.Count != 0) - { - var responseType = responseTypeAttributes.First().Type; - genericType = responseType; - } - - if (genericType.IsEquivalentTo(typeof(ContentResult)) || genericType.IsEquivalentTo(typeof(FileStreamResult))) - { - operation.Responses["200"] = new OpenApiResponse - { - Description = "OK", - Content = new Dictionary - { - [contentType] = new() - } - }; - } - else if (genericType == typeof(ActionResult)) - { - operation.Responses["200"] = new OpenApiResponse { Description = "OK" }; - } - else - { - OpenApiSchema schema; - if (genericType.IsGenericType && genericType.GetGenericTypeDefinition() == typeof(ActionResult<>)) - schema = context.SchemaGenerator.GenerateSchema(genericType.GetGenericArguments().FirstOrDefault(), - context.SchemaRepository); - else - schema = context.SchemaGenerator.GenerateSchema(genericType, context.SchemaRepository); - - operation.Responses["200"] = new OpenApiResponse - { - Description = "OK", - Content = new Dictionary - { - [contentType] = new() { Schema = schema } - } - }; - } - } -} \ No newline at end of file diff --git a/Endpoint/Configuration/SwaggerOptions/ConfigureSwaggerOptions.cs b/Endpoint/Configuration/SwaggerOptions/ConfigureSwaggerOptions.cs index 8b40ca01c0d731bd3ebecaf8e1f8e0645fe6ddb2..55d5e9c735145d9d8097e2cd0eff74783e7ac24a 100644 GIT binary patch literal 3316 zcmbuCTW`}q5QXO%iT|*QcxVMO@7x5UfGTklE%2PWZfa>-m<0%r#{}_E0Y)~GR-qvZ)#bXNm3`x>|4PRv=KzhYU7 z-Z>W5Z1~9UshzPV?#;0_8?0=z_K44J#*e<`Cj-A?misc#yiP9sZ$PV_e&lD4>LKf5 z&t*(2+q#8?z^Qe7t!?*g^(`k4jyMx@T*BvooiorE8bakNY5}|&_q>l@>JGO-e&|{9 zCB6Gm3|X{;$0dH|{VS+2dA0zF_e3I2KX622l&Uaw7{&eCW6v>WllE;ejdhlMT{^~M zaas|JYDZDF0vLAq5vw$qII-?6$rEM#-~7vYo#*+cOx}hai3`fP5DWH{PeTMhc;{o; z8t^XRlILIA-3PPIyHm7r&qnm0UAopQYC6Dv@v|c9idpDxEi|d?r~|7TozuUfyk?i?(ZaK+Nja2M%!R!Lp>maL)vwlKmyy@%x_!$_ zBu23FGJ6sp>D@mOvDw7@9489f$E!VTiyOnyRGzC_~3UORDHYRhL z9h%1SHQ4=Y(M>4l-Xl;`t(I6C!v{sx@hF~jqX?^;fI9gYIr$|Y*M4cLP4KZpvikd7 zx->@vYx4KpPiS`PessjDI={6Fl&5*6j)lACuk=i-5X`U5C(XMXc znm@67smu1K!_cDgpsI~G_}newzT>OBTf&U487-95XKHRRw(y&9Tqfc5uj;{rd`j9OvlU+$#OSC#r%pdf~K7_NwtpzwN) z?go#|mU|y?)4?`RVyflZSRb_N0qZ>Rh*{CG9T~YnUrL3r&<-WfE@mbztu{eiS(E8? z58@rv=&^8L<=}iTehMLHKI% zJ8h;`#RE8T<7`#lk;G?kMI8gqO=hpH>!F9~Npey1JdBzdo!(Lj_(1wAXidTh{{-uC z2U-sYd@lsguNm(F77Gpv!ni$T#4SAaTp*Mk<4(&qHQP z**PJ{I<%4=1w`=qglt2(yGP3sm6ip_K<5eX7tp#xDap{m)=-6B=V6C@2We73>Gu$v zG(Mxnu^Gssps%LTd+GLdX8{YDBCIHnxV&iN?Z#*c0p&)#6OWcHNEJ@Md>4EJb}hY& zCRNC3YCb2TGnj3pE;#I~va~LI+jTvJ!4SdWROef*=&)p*fxEh3-(xX zbR6X&l>U4?wsbgpTRDZoy7ib&9ES8`E=u5V)cA1GtPLxyGZ-$Gn0q>_9g?ju?R{Nm ovOkA*_)NpW(Gc6_UjcIZHY-F!M(c1yG-ybssGO-+soUYhU-nEP4*&oF diff --git a/Endpoint/Configuration/SwaggerOptions/DefaultValues.cs b/Endpoint/Configuration/SwaggerOptions/DefaultValues.cs deleted file mode 100644 index 7ad61a9..0000000 --- a/Endpoint/Configuration/SwaggerOptions/DefaultValues.cs +++ /dev/null @@ -1,51 +0,0 @@ -using Microsoft.AspNetCore.Mvc.ApiExplorer; -using Microsoft.AspNetCore.Mvc.ModelBinding; -using Microsoft.OpenApi.Models; -using Swashbuckle.AspNetCore.SwaggerGen; -using System; -using System.Linq; -using System.Text.Json; - -namespace Mirea.Api.Endpoint.Configuration.SwaggerOptions; - -public class DefaultValues : IOperationFilter -{ - public void Apply(OpenApiOperation operation, OperationFilterContext context) - { - var apiDescription = context.ApiDescription; - operation.Deprecated |= apiDescription.IsDeprecated(); - - foreach (var responseType in context.ApiDescription.SupportedResponseTypes) - { - var responseKey = responseType.IsDefaultResponse ? "default" : responseType.StatusCode.ToString(); - var response = operation.Responses[responseKey]; - - foreach (var contentType in response.Content.Keys) - { - if (responseType.ApiResponseFormats.All(x => x.MediaType != contentType)) - response.Content.Remove(contentType); - } - } - - if (operation.Parameters == null) - return; - - foreach (var parameter in operation.Parameters) - { - var description = apiDescription.ParameterDescriptions.First(p => p.Name == parameter.Name); - - parameter.Description ??= description.ModelMetadata.Description; - - if (parameter.Schema.Default == null && - description.DefaultValue != null && - description.DefaultValue is not DBNull && - description.ModelMetadata is ModelMetadata modelMetadata) - { - var json = JsonSerializer.Serialize(description.DefaultValue, modelMetadata.ModelType); - parameter.Schema.Default = OpenApiAnyFactory.CreateFromJson(json); - } - - parameter.Required |= description.IsRequired; - } - } -} \ No newline at end of file diff --git a/Endpoint/Configuration/SwaggerOptions/EnumSchemaFilter.cs b/Endpoint/Configuration/SwaggerOptions/EnumSchemaFilter.cs deleted file mode 100644 index f64fc87..0000000 --- a/Endpoint/Configuration/SwaggerOptions/EnumSchemaFilter.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Microsoft.OpenApi.Any; -using Microsoft.OpenApi.Models; -using Swashbuckle.AspNetCore.SwaggerGen; -using System; -using System.Linq; - -namespace Mirea.Api.Endpoint.Configuration.SwaggerOptions; - -public class EnumSchemaFilter : ISchemaFilter -{ - public void Apply(OpenApiSchema schema, SchemaFilterContext context) - { - if (!context.Type.IsEnum) - return; - - schema.Enum.Clear(); - - var enumValues = Enum.GetNames(context.Type) - .Select(name => new OpenApiString(name)) - .ToList(); - - foreach (var value in enumValues) - schema.Enum.Add(value); - - schema.Type = "string"; - schema.Format = null; - } -} \ No newline at end of file diff --git a/Endpoint/Configuration/SwaggerOptions/ExampleFilter.cs b/Endpoint/Configuration/SwaggerOptions/ExampleFilter.cs deleted file mode 100644 index 060aa52..0000000 --- a/Endpoint/Configuration/SwaggerOptions/ExampleFilter.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Microsoft.OpenApi.Models; -using Mirea.Api.Endpoint.Common.Attributes; -using Swashbuckle.AspNetCore.SwaggerGen; -using System.Reflection; - -namespace Mirea.Api.Endpoint.Configuration.SwaggerOptions; - -public class ExampleFilter : ISchemaFilter -{ - public void Apply(OpenApiSchema schema, SchemaFilterContext context) - { - var att = context.ParameterInfo?.GetCustomAttribute(); - if (att != null) - schema.Example = new Microsoft.OpenApi.Any.OpenApiString(att.Value); - } -} \ No newline at end of file diff --git a/Endpoint/Configuration/SwaggerOptions/TagSchemeFilter.cs b/Endpoint/Configuration/SwaggerOptions/TagSchemeFilter.cs deleted file mode 100644 index 4c2be6f..0000000 --- a/Endpoint/Configuration/SwaggerOptions/TagSchemeFilter.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc.Controllers; -using Microsoft.OpenApi.Models; -using Swashbuckle.AspNetCore.SwaggerGen; -using System.Linq; -using System.Reflection; - -namespace Mirea.Api.Endpoint.Configuration.SwaggerOptions; - -public class TagSchemeFilter : IOperationFilter -{ - public void Apply(OpenApiOperation operation, OperationFilterContext context) - { - if (context.ApiDescription.ActionDescriptor is not ControllerActionDescriptor controllerActionDescriptor) - return; - - var controllerType = controllerActionDescriptor.ControllerTypeInfo; - - var tagsAttribute = controllerType.GetCustomAttributes(inherit: true).FirstOrDefault(); - - if (tagsAttribute == null) - { - var baseType = controllerType.BaseType; - while (baseType != null) - { - tagsAttribute = baseType.GetCustomAttributes(inherit: true).FirstOrDefault(); - if (tagsAttribute != null) - break; - - baseType = baseType.BaseType; - } - } - - if (tagsAttribute == null) - return; - - operation.Tags ??= []; - operation.Tags.Add(new OpenApiTag { Name = tagsAttribute.Tags[0] }); - } -} \ No newline at end of file diff --git a/Endpoint/Endpoint.csproj b/Endpoint/Endpoint.csproj index 1215604..2e64ba9 100644 --- a/Endpoint/Endpoint.csproj +++ b/Endpoint/Endpoint.csproj @@ -9,7 +9,7 @@ docs.xml $(NoWarn);1591 false - + @@ -20,63 +20,50 @@ - - - + + + runtime; build; native; contentfiles; analyzers; buildtransitive all - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - - - - + + - - - - - + + + + + - + - + - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + @@ -86,7 +73,6 @@ - \ No newline at end of file diff --git a/Endpoint/Program.cs b/Endpoint/Program.cs index 7edc3b9620dcb044e1715f81951014a637da726d..4b6af6078cf13e2502044ab47bd0b19082168c96 100644 GIT binary patch literal 16702 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 GUfuyZ=LDw! literal 1407 zcmd^9O>f&U488YP1j3F*l73}vddgY@4X`>!yp4r{BGB}0;v4T1mrC|P!z1p|uq zGGG@2BAF zT4u#Jtu_WUBCM|AkK_+6+^=TC@*FXJ7UY_1B}*>|m^*a=s&*>ogS!tXC&a5@qp>BxkK>Y;&Ay;{K zbso4?*{iqt-Yo+Spg+9sPvYCUh@p@(1^{ndnHQSX7sr&x=Yi9J|>H0O5GM+ zjxSI8eZ`H^oc{$IZ=nZ_8=}lztD +// Этот код создан программой. +// Исполняемая версия:4.0.30319.42000 +// +// Изменения в этом файле могут привести к неправильной работе и будут потеряны в случае +// повторной генерации кода. +// +//------------------------------------------------------------------------------ + +namespace Mirea.Api.Endpoint.Resources { + using System; + + + /// + /// Класс ресурса со строгой типизацией для поиска локализованных строк и т.д. + /// + // Этот класс создан автоматически классом StronglyTypedResourceBuilder + // с помощью такого средства, как ResGen или Visual Studio. + // Чтобы добавить или удалить член, измените файл .ResX и снова запустите ResGen + // с параметром /str или перестройте свой проект VS. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + public class SharedResources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal SharedResources() { + } + + /// + /// Возвращает кэшированный экземпляр ResourceManager, использованный этим классом. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Mirea.Api.Endpoint.Resources.SharedResources", typeof(SharedResources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Перезаписывает свойство CurrentUICulture текущего потока для всех + /// обращений к ресурсу с помощью этого класса ресурса со строгой типизацией. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Ищет локализованную строку, похожую на Please provide this traceId to the administrator for further investigation.. + /// + public static string ProvideTraceId { + get { + return ResourceManager.GetString("ProvideTraceId", resourceCulture); + } + } + + /// + /// Ищет локализованную строку, похожую на Resource not found.. + /// + public static string ResourceNotFound { + get { + return ResourceManager.GetString("ResourceNotFound", resourceCulture); + } + } + + /// + /// Ищет локализованную строку, похожую на An unexpected error occurred.. + /// + public static string UnexpectedErrorOccurred { + get { + return ResourceManager.GetString("UnexpectedErrorOccurred", resourceCulture); + } + } + } +} diff --git a/Endpoint/Resources/SharedResources.resx b/Endpoint/Resources/SharedResources.resx new file mode 100644 index 0000000..9fd9950 --- /dev/null +++ b/Endpoint/Resources/SharedResources.resx @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Please provide this traceId to the administrator for further investigation. + + + Resource not found. + + + An unexpected error occurred. + + \ No newline at end of file diff --git a/Endpoint/Resources/SharedResources.ru-RU.resx b/Endpoint/Resources/SharedResources.ru-RU.resx new file mode 100644 index 0000000..baed993 --- /dev/null +++ b/Endpoint/Resources/SharedResources.ru-RU.resx @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + + + + + Неизвестная ошибка + + \ No newline at end of file diff --git a/Security/Security.csproj b/Security/Security.csproj index dd9d12a..dee6605 100644 --- a/Security/Security.csproj +++ b/Security/Security.csproj @@ -8,8 +8,6 @@ - - diff --git a/SqlData/Application/Application.csproj b/SqlData/Application/Application.csproj index 46dda66..7bee919 100644 --- a/SqlData/Application/Application.csproj +++ b/SqlData/Application/Application.csproj @@ -6,13 +6,13 @@ - - - - - - - + + + + + + + diff --git a/SqlData/Persistence/DependencyInjection.cs b/SqlData/Persistence/DependencyInjection.cs index b9376a900bd066c2be9c4a42fd19d09bca9aa890..fba6271f2ce67cea0dc794ef5fb504d108c96fab 100644 GIT binary patch literal 12096 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 - - - + +