بررسی دو نکته (ترفند) کاربردی در SQL Server
چنانچه از SSIS Package برای اینکار استفاده شود، با فرض اینکه در مرحله قبل Schema تمامی اشیاء بانک منتقل شده است، Control Flow این Package شامل Stepهای زیر میباشد:
گام اول - غیر فعال کردن تمامی Constraintهای جداول
برای این منظور از Object موسوم به Execute SQL Task به این صورت استفاده میشود که در بخش SQL Statement دستور زیر نوشته شود:
exec sp_MSforeachtable 'ALTER TABLE ? NOCHECK CONSTRAINT ALL'
برای این منظور از Object موسوم به Transfer SQL Server Objects Task به صورت زیر استفاده میشود :
در بخش Object تغییرات زیر اعمال شود:
- در قسمت Destination ، پروپرتی CopyData با مقدار True و ExistingData با مقدار Append تنظیم شود.
- در قسمت Destination Copy & Option ، پروپرتی CopyAllTables در بخش ObjectsToCopy با مقدارTrue تنظیم شود.
گام سوم - فعال کردن مجدد Constraintهای جداول
برای این منظور از Object موسوم به Execute SQL Task به صورت زیر استفاده میشود :
در بخش SQL Statement دستور زیر نوشته شود:
exec sp_MSforeachtable 'ALTER TABLE ? CHECK CONSTRAINT ALL'
برای مثال شکل SSIS Package فوق به صورت تصویر فوق است.
معرفی تعدادی آنالیز کنندهی کد که به عنوان افزونهی کامپایلر #C قابل استفاده هستند
Microsoft.CodeAnalysis.NetAnalyzers
این افزونه جزئی از SDK دات نت 5 است و نیازی به نصب مجزا را ندارد. البته اگر میخواهید نگارشهای جدیدتر آنرا پیش از یکی شدن با SDKهای بعدی مورد آزمایش قرار دهید، میتوان آنرا به صورت صریحی نیز به کامپایلر معرفی کرد. این افزونهی جایگزین FxCop است و پس از ارائهی آن، FxCop را منسوخ شده اعلام کردند.
Meziantou.Analyzer
یکسری نکات بهبود کیفیت کدها که توسط Meziantou در طی سالهای متمادی جمع آوری شدهاند، تبدیل به افزونهی فوق شدهاند.
Microsoft.VisualStudio.Threading.Analyzers
این افزونه نکاتی را در مورد مشکلات Threading موجود در کدها، گوشزد میکند.
Microsoft.CodeAnalysis.BannedApiAnalyzers
با استفاده از این افزونه میتوان استفادهی از یکسری کدها را ممنوع کرد. برای مثال استفادهی از System.DateTimeOffset.DateTime، در سراسر کدها ممنوع شده و استفادهی از System.DateTimeOffset.UtcDateTime پیشنهاد شود.
AsyncFixer و Asyncify
این دو افزونه، مشکلات متداول در حین کار با کدهای async را گوشزد میکنند.
ClrHeapAllocationAnalyzer
این افزونه مکانهایی از کد را مشخص میکنند که در آنها تخصیص حافظه صورت گرفتهاست. کاهش این مکانها میتواند به بالا رفتن کارآیی برنامه کمک کنند.
SonarAnalyzer.CSharp
مجموعهی معروف Sonar، که تعداد قابل ملاحظهای بررسی کنندهی کد را به پروژهی شما اضافه میکنند.
روش معرفی سراسری افزونههای فوق به تمام پروژههای یک Solution
میتوان تنظیمات زیر را به یک تک پروژه اعمال کرد که برای اینکار نیاز است فایل csproj آنرا ویرایش نمود و یا میتوان یک تک فایل ویژه را به نام Directory.Build.props ایجاد کرد و آنرا به صورت زیر تکمیل نمود. محل قرارگیری این فایل، در ریشهی Solution و در کنار فایل sln میباشد.
<Project> <PropertyGroup> <AnalysisLevel>latest</AnalysisLevel> <AnalysisMode>AllEnabledByDefault</AnalysisMode> <CodeAnalysisTreatWarningsAsErrors>true</CodeAnalysisTreatWarningsAsErrors> <EnableNETAnalyzers>true</EnableNETAnalyzers> <EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild> <Nullable>enable</Nullable> <TreatWarningsAsErrors>true</TreatWarningsAsErrors> <RunAnalyzersDuringBuild>true</RunAnalyzersDuringBuild> <RunAnalyzersDuringLiveAnalysis>true</RunAnalyzersDuringLiveAnalysis> <!-- CA2007: Consider calling ConfigureAwait on the awaited task MA0004: Use Task.ConfigureAwait(false) as the current SynchronizationContext is not needed CA1056: Change the type of property 'Url' from 'string' to 'System.Uri' CA1054: Change the type of parameter of the method to allow a Uri to be passed as a 'System.Uri' object CA1055: Change the return type of method from 'string' to 'System.Uri' --> <NoWarn>$(NoWarn);CA2007;CA1056;CA1054;CA1055;MA0004</NoWarn> <NoError>$(NoError);CA2007;CA1056;CA1054;CA1055;MA0004</NoError> <Deterministic>true</Deterministic> <Features>strict</Features> <ReportAnalyzer>true</ReportAnalyzer> </PropertyGroup> <ItemGroup> <PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="5.0.1"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> </PackageReference> <PackageReference Include="Meziantou.Analyzer" Version="1.0.639"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> </PackageReference> <PackageReference Include="Microsoft.VisualStudio.Threading.Analyzers" Version="16.8.55"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> </PackageReference> <PackageReference Include="Microsoft.CodeAnalysis.BannedApiAnalyzers" Version="3.3.2"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> </PackageReference> <PackageReference Include="AsyncFixer" Version="1.3.0"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> </PackageReference> <PackageReference Include="Asyncify" Version="0.9.7"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> </PackageReference> <PackageReference Include="ClrHeapAllocationAnalyzer" Version="3.0.0"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> </PackageReference> <PackageReference Include="SonarAnalyzer.CSharp" Version="8.16.0.25740"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> </PackageReference> </ItemGroup> <ItemGroup> <AdditionalFiles Include="$(MSBuildThisFileDirectory)BannedSymbols.txt" Link="Properties/BannedSymbols.txt" /> </ItemGroup> </Project>
- در تنظیمات فوق، مواردی مانند AnalysisLevel، در مطلب «کامپایلر C# 9.0، خطاها و اخطارهای بیشتری را نمایش میدهد» پیشتر بررسی شدهاند.
- در اینجا Nullable به true تنظیم شدهاست. اگر قرار است یک پروژهی جدید را شروع کنید، بهتر است این ویژگی را نیز فعال کنید. بسیاری از APIهای دات نت 5 جهت مشخص سازی خروجی نال و یا غیرنال آنها، بازنویسی و تکمیل شدهاند و بدون استفاده از این ویژگی، بسیاری از راهنماییهای ارزندهی دات نت 5 را از دست خواهید داد. اساسا بدون فعالسازی این ویژگی، از قابلیتهای #C مدرن استفاده نمیکنید.
- وجود این PackageReference ها، به معنای بالا رفتن حجم نهایی قابل ارائهی پروژه نیست؛ چون به صورت PrivateAssets و analyzers تعریف شدهاند و فقط در حین پروسهی کامپایل، جهت ارائهی راهنماییهای بیشتر، تاثیرگذار خواهند بود.
- این تنظیمات طوری چیده شدهاند که تا حد ممکن «درد آور» باشند! برای اینکار CodeAnalysisTreatWarningsAsErrors و TreatWarningsAsErrors به true تظیم شدهاند تا حتی اخطارها نیز به صورت خطای کامپایلر گزارش شوند؛ تا مجبور به رفع آنها شویم.
- در اینجا فایل BannedSymbols.txt را نیز مشاهده میکنید که مرتبط است به BannedApiAnalyzers. میتوان در کنار فایل Directory.Build.props، فایل جدید BannedSymbols.txt را با این محتوا ایجاد کرد:
# https://github.com/dotnet/roslyn-analyzers/blob/master/src/Microsoft.CodeAnalysis.BannedApiAnalyzers/BannedApiAnalyzers.Help.md P:System.DateTime.Now;Use System.DateTime.UtcNow instead P:System.DateTimeOffset.Now;Use System.DateTimeOffset.UtcNow instead P:System.DateTimeOffset.DateTime;Use System.DateTimeOffset.UtcDateTime instead
روش کاهش تعداد خطاهای نمایش داده شده
اگر از فایل Directory.Build.props فوق استفاده کرده و یکبار دستور dotnet restore را جهت بازیابی وابستگیهای آن اجرا کنید، با تعداد خطاهایی که در IDE خود مشاهده خواهید کرد، شگفتزده خواهید شد! به همین جهت برای کنترل آنها میتوان فایل جدید editorconfig. را به نحو زیر در کنار فایل Directory.Build.props ایجاد و تکمیل کرد:
[*.cs] # MA0026 : Complete the task dotnet_diagnostic.MA0026.severity = suggestion # CA1308: In method 'urlToLower', replace the call to 'ToLowerInvariant' with 'ToUpperInvariant' (CA1308) dotnet_diagnostic.CA1308.severity = suggestion # CA1040: Avoid empty interfaces dotnet_diagnostic.CA1040.severity = suggestion # CA1829 Use the "Count" property instead of Enumerable.Count() dotnet_diagnostic.CA1829.severity = suggestion # Use 'Count' property here instead. dotnet_diagnostic.S2971.severity = suggestion # S1135 : Complete the task dotnet_diagnostic.S1135.severity = suggestion # S2479: Replace the control character at position 7 by its escape sequence dotnet_diagnostic.S2479.severity = suggestion # CA2007: Consider calling ConfigureAwait on the awaited task dotnet_diagnostic.CA2007.severity = none # MA0004: Use Task.ConfigureAwait(false) as the current SynchronizationContext is not needed dotnet_diagnostic.MA0004.severity = none # CA1056: Change the type of property 'Url' from 'string' to 'System.Uri' dotnet_diagnostic.CA1056.severity = suggestion # CA1054: Change the type of parameter of the method to allow a Uri to be passed as a 'System.Uri' object dotnet_diagnostic.CA1054.severity = suggestion # CA1055: Change the return type of method from 'string' to 'System.Uri' dotnet_diagnostic.CA1055.severity = suggestion # S4457: Split this method into two, one handling parameters check and the other handling the asynchronous code. dotnet_diagnostic.S4457.severity = none # AsyncFixer01: Unnecessary async/await usage dotnet_diagnostic.AsyncFixer01.severity = suggestion # AsyncFixer02: Long-running or blocking operations inside an async method dotnet_diagnostic.AsyncFixer02.severity = error # VSTHRD103: Call async methods when in an async method dotnet_diagnostic.VSTHRD103.severity = error # AsyncFixer03: Fire & forget async void methods dotnet_diagnostic.AsyncFixer03.severity = error # VSTHRD100: Avoid async void methods dotnet_diagnostic.VSTHRD100.severity = error # VSTHRD101: Avoid unsupported async delegates dotnet_diagnostic.VSTHRD101.severity = error # VSTHRD107: Await Task within using expression dotnet_diagnostic.VSTHRD107.severity = error # AsyncFixer04: Fire & forget async call inside a using block dotnet_diagnostic.AsyncFixer04.severity = error # VSTHRD110: Observe result of async calls dotnet_diagnostic.VSTHRD110.severity = error # VSTHRD002: Avoid problematic synchronous waits dotnet_diagnostic.VSTHRD002.severity = suggestion # MA0045: Do not use blocking call (make method async) dotnet_diagnostic.MA0045.severity = suggestion # AsyncifyInvocation: Use Task Async dotnet_diagnostic.AsyncifyInvocation.severity = error # AsyncifyVariable: Use Task Async dotnet_diagnostic.AsyncifyVariable.severity = error # VSTHRD111: Use ConfigureAwait(bool) dotnet_diagnostic.VSTHRD111.severity = none # MA0022: Return Task.FromResult instead of returning null dotnet_diagnostic.MA0022.severity = error # VSTHRD114: Avoid returning a null Task dotnet_diagnostic.VSTHRD114.severity = error # VSTHRD200: Use "Async" suffix for async methods dotnet_diagnostic.VSTHRD200.severity = suggestion # MA0040: Specify a cancellation token dotnet_diagnostic.MA0032.severity = suggestion # MA0040: Flow the cancellation token when available dotnet_diagnostic.MA0040.severity = suggestion # MA0079: Use a cancellation token using .WithCancellation() dotnet_diagnostic.MA0079.severity = suggestion # MA0080: Use a cancellation token using .WithCancellation() dotnet_diagnostic.MA0080.severity = error #AsyncFixer05: Downcasting from a nested task to an outer task. dotnet_diagnostic.AsyncFixer05.severity = error # ClrHeapAllocationAnalyzer ---------------------------------------------------- # HAA0301: Closure Allocation Source dotnet_diagnostic.HAA0301.severity = suggestion # HAA0601: Value type to reference type conversion causing boxing allocation dotnet_diagnostic.HAA0601.severity = suggestion # HAA0302: Display class allocation to capture closure dotnet_diagnostic.HAA0302.severity = suggestion # HAA0101: Array allocation for params parameter dotnet_diagnostic.HAA0101.severity = suggestion # HAA0603: Delegate allocation from a method group dotnet_diagnostic.HAA0603.severity = suggestion # HAA0602: Delegate on struct instance caused a boxing allocation dotnet_diagnostic.HAA0602.severity = suggestion # HAA0401: Possible allocation of reference type enumerator dotnet_diagnostic.HAA0401.severity = silent # HAA0303: Lambda or anonymous method in a generic method allocates a delegate instance dotnet_diagnostic.HAA0303.severity = silent # HAA0102: Non-overridden virtual method call on value type dotnet_diagnostic.HAA0102.severity = silent # HAA0502: Explicit new reference type allocation dotnet_diagnostic.HAA0502.severity = none # HAA0505: Initializer reference type allocation dotnet_diagnostic.HAA0505.severity = silent
dotnet_diagnostic.CA1308.severity = suggestion
یک نکته: در ویندوز نمیتوانید یک فایل تنها پسوند دار را به صورت معمولی در windows explorer ایجاد کنید. نام این فایل را به صورت .editorconfig. با دو نقطهی ابتدایی و انتهایی وارد کنید. خود ویندوز نقطهی پایانی را حذف میکند.
روش صرفنظر کردن از یک خطا، تنها در یک قسمت از کد
فرض کنید نمیخواهید خطای CA1052 را تبدیل به یک suggestion سراسری کنید و فقط میخواهید که در قطعهی خاصی از کدهای خود، آنرا خاموش کنید. به همین جهت بجای اضافه کردن آن به فایل editorconfig.، باید از ویژگی SuppressMessage به صورت زیر استفاده نمائید:
[SuppressMessage("Microsoft.Usage", "CA1052:Type 'Program' is a static holder type but is neither static nor NotInheritable", Justification = "We need it for our integration tests this way.")] [SuppressMessage("Microsoft.Usage", "RCS1102:Type 'Program' is a static holder type but is neither static nor NotInheritable", Justification = "We need it for our integration tests this way.")] [SuppressMessage("Microsoft.Usage", "S1118:Type 'Program' is a static holder type but is neither static nor NotInheritable", Justification = "We need it for our integration tests this way.")] public class Program { }
At Microsoft Build Live today, we are sharing a first look at our plans for .NET Core 3. The highlight of .NET Core 3 is support for Windows desktop applications, specifically Windows Forms, Windows Presentation Framework (WPF), and UWP XAML. You will be able to run new and existing Windows desktop applications on .NET Core and enjoy all the benefits that .NET Core has to offer.
نگاهی دقیق به ASP.NET CORE
ASP.NET Core is a completely new web framework for building modern cloud-based web applications. In this presentation learn all about ASP.NET Core and including the latest features and innovations in MVC. You’ll see how you can build applications that run cross-platform on Windows, Mac and Linux via .NET Core. You’ll also see how ASP.NET Core MVC gives you a unified web programming model for building both web UI and web APIs.
معرفی DNTProfiler
هدیهی نوروزی سایت net tips. پروژهی پروفایلر سورس بازی است که با EF 6.x و همچنین NHibernate 4.x سازگار است. این پروژه از دو قسمت کلاینت و سرور تشکیل میشود.
نصب کلاینت EF برنامهی DNTProfiler
تفاوتی نمیکند که برنامهی شما وبی است یا ویندوزی؛ برای هر دو حالت ابتدا دستور ذیل را در کنسول پاورشل نیوگت اجرا کنید:
PM> Install-Package DNTProfiler.EntityFramework.Core
<configuration> <entityFramework> <interceptors> <interceptor type="DNTProfiler.EntityFramework.Core.DatabaseLogger, DNTProfiler.EntityFramework.Core"> <parameters> <parameter value="http://localhost:8080" /> <parameter value="|DataDirectory|\ErrorsLog.Log" /> </parameters> </interceptor> </interceptors> </entityFramework> </configuration>
دریافت و راه اندازی برنامهی DNTProfiler
آخرین نگارش برنامهی DNTProfiler را از برگهی releases مخزن کد آن میتوانید دریافت کنید:
https://github.com/VahidN/DNTProfiler/releases
این برنامه برای دات نت 4 نوشته شدهاست. بنابراین اگر هنوز از ویندوز XP استفاده میکنید، امکان کار کردن با آنرا خواهید داشت.
البته بستهی نیوگت DNTProfiler.EntityFramework.Core آن برای دات نت 4 و 4.5 تهیه شدهاست و به صورت خودکار بر اساس ساختار پروژهی شما، یکی از آنها نصب خواهد شد.
تا اینجا کار راه اندازی این برنامه به پایان میرسد. برای استفادهی از آن باید ابتدا برنامهی DNTProfiler را اجرا کنید. این برنامه به پیامهای رسیدهی از برنامهی اصلی شما (ارسال شده توسط DNTProfiler.EntityFramework.Core) گوش فرا میدهد و سپس شروع به آنالیز آنها خواهد کرد. ساختار این تبادل اطلاعات هم بر اساس تهیهی یک ASP.NET Self host Web API است.
این برنامه به صورت ماژولار تهیه شدهاست و تمام آنالیز کنندههای آن در حقیقت یک پلاگین هستند (در حال حاضر دارای 32 پلاگین است). این پلاگینها در گروههای Alerts (برای مثال یافتن جوینهای تکراری و یک سری موارد بهینه سازی سرعت)، Loggers (طبقه بندی خام اطلاعات رسیده)، Visualizers (نمایش بصری اطلاعات رسیده) قرار میگیرند.
نظرات، پیشنهادات و همکاری
لطفا برای طرح سؤالات و ارائهی پیشنهادات خود در زمینهی این پروژه، به قسمت اختصاصی آن در سایت مراجعه نمائید:
https://www.dntips.ir/projects/details/21
var container = new UnityContainer();
container.RegisterType<ISomeService, SomeService>(new PerRequestLifetimeManager()); container.RegisterType<ISomeBusiness, SomeBusiness>(new PerRequestLifetimeManager()); container.RegisterType<ISomeController, SomeController>(new PerRequestLifetimeManager());
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
var someService=(ISomeService)DependencyResolver.Current.GetService(typeof(ISomeService)); var data=someService.GetData();
در لایه سرویس یک کلاس Service Factory داریم که قرار است همه سرویسها، برای برقراری ارتباط با یکدیگر از آن استفاده کنند.این کلاس معمولا در لایه سرویس به اشکال گوناگونی پیاده سازی میشود که کارش وهه سازی از Interfaceهای درخواستی است. اما برای یکپارچه کردن آن با Unity من آنرا به شکل زیر پیاده سازی کرده ام
public class ServiceFactory : MarshalByRefObject { static IUnityContainer uContainer = new UnityContainer(); public static Type DataContextType { get; set; } public static void Initialise(IUnityContainer unityContainer, Type dbContextType) { uContainer = unityContainer; DataContextType = dbContextType; uContainer.RegisterType(typeof(BaseDataContext), DataContextType, new HierarchicalLifetimeManager()); } public static T Create<T>() { return (T)Activator.CreateInstance<T>(); } public static T Create<T>(string fullTypeName) { return (T)System.Reflection.Assembly.GetExecutingAssembly().CreateInstance(fullTypeName); } public static T Create<T>(Type entityType) { return (T)Activator.CreateInstance(entityType); } public static dynamic Create(Type entityType) { return Activator.CreateInstance(entityType); } public static T Get<T>() { return uContainer.Resolve<T>(); } public static object Get(Type type) { return uContainer.Resolve(type); } }
در این کلاس ما بجای ایجاد داینامیک آبجکتها، از Unity استفاده کردهایم. در همان ابتدا که برنامهی وب ما برای اولین بار اجرا میشود و بعد از Register کردن کلاسها، میتوانیم container را به صورت پارامتر سازنده به کلاس Service Factory ارسال کنیم. به این ترتیب برای استفاده از سرویسها در لایه Business از Unity بهره میبریم.
البته استفاده از Unity برای DataContext خیلی منطقی نیست و بهتر است نوع DataContext را در ابتدا بگیریم و هرجا نیاز داشتیم با استفاده از متد Create از آن وهله سازی بکنیم.
Install-Package Breeze.WebApi2.EF6
var instance = breeze.config.initializeAdapterInstance("ajax", "angular"); instance.setHttp($http);
Install-Package Breeze.Angular
var manager = new breeze.EntityManager({ dataService: dataService, metadataStore: metadataStore, saveOptions: new breeze.SaveOptions({ allowConcurrentSaves: true, tag: [{}] }) });
var dataService = new breeze.DataService({ serviceName: "/breeze/"+ "Automobile", hasServerMetadata: false, namingConvention: breeze.NamingConvention.camelCase }); var metadataStore = new breeze.MetadataStore({});
var myMetadataStore = new breeze.MetadataStore(); myMetadataStore.addEntityType({...});
var customer = function () { this.City = ""; }; myMetadataStore.registerEntityTypeCtor("Customer", customer);
[BreezeController] public class AutomobileController : ApiController { readonly EFContextProvider<ApplicationDbContext> _contextProvider = new EFContextProvider<ApplicationDbContext>(); [HttpGet] public string Metadata() { return _contextProvider.Metadata(); } [HttpGet] public IQueryable<Customer> Customers() { return _contextProvider.Context.Customers; } [System.Web.Http.HttpPost] public SaveResult SaveChanges(JObject saveBundle) { _contextProvider.BeforeSaveEntitiesDelegate = BeforeSaveEntities; _contextProvider.AfterSaveEntitiesDelegate = afterSaveEntities; return _contextProvider.SaveChanges(saveBundle); } protected Dictionary<Type, List<EntityInfo>> BeforeSaveEntities(Dictionary<Type, List<EntityInfo>> saveMap) { } private void afterSaveEntities(Dictionary<Type, List<EntityInfo>> saveMap, List<KeyMapping> keyMappings) { } }
manger.saveChanges().then(function success() { }, function failer(e) { });
manger.rejectChanges()
کوئری:بعد از تعریف Entity Manger میتوانیم کوئری خود را اجرا نماییم. کوئری ما شامل گرفتن اطلاعات از جدول Customer، با مرتب سازی بر روی فیلد آیدی میباشد و با اجرا کردن کوئری میتوانیم موفقیت یا عدم موفقیت آنرا بررسی نماییم.
var query = breeze.EntityQuery .from("Customer") .orderBy("Id"); var result= manager.executeQuery(query); result.then(querySucceeded) .fail(queryFailed); query = query.where("Id", "==", 1)
var predicate = new breeze.Predicate("Id", "==", false); query = query.where(predicate) var p1 = new breeze.Predicate("IsArchived", "==", false); var p2 = breeze.Predicate("IsDone", "==", false); var predicate = p1.and(p2); query = query.where(predicate).orderBy("Id")
?$filter=IsArchived eq false&IsDone eq false &$orderby=Id
اعتبارسنجی :اعتبارسنجی در breeze، هم در سمت کلاینت و هم در سمت سرور امکان پذیر میباشد که در مثالی، در قسمت بعدی، validator سفارشی خودمان را خواهیم ساخت و به entity مورد نظر اعمال خواهیم کرد.
breeze.Validator.required({ allowEmptyStrings: true });
ردیابی تغییرات: هر آیتم Entity دارای EntityAspect است که وضعیت آنرا مشخص میکند و میتواند یکی از وضعیتهای Added،Modified،Deleted،Detached،Unchanged باشد. با مشخص کردن حالت هر آیتم، با فراخوانی SaveChanges تغییرات بر روی دیتابیس اعمال میگردد.
manager.createEntity('Customer', jsonValue);
manager.createEntity("Customer", jsonValue, breeze.EntityState.Modified, breeze.MergeStrategy.OverwriteChanges)
manager.createEntity("Customer", item, breeze.EntityState.Deleted)
برای اشنایی بیشتر با امکانات Breeze، قصد داریم یک سایت ایجاد آگهی را راه اندازی کنیم. پیش نیازهای ضروری این بخش typescript ،angularjs ،requirejs هستند. قصد داریم سایتی را برای آگهیهای خرید و فروش خودرو، مشابه با سایت باما ایجاد نماییم:
امکانات این سایت:
Install-Package angularjs Install-Package angularjs.TypeScript.DefinitelyTyped Install-Package bootstrap Install-Package bootstrap.TypeScript.DefinitelyTyped Install-Package jQuery Install-Package jquery.TypeScript.DefinitelyTyped Install-Package RequireJS Install-Package requirejs.TypeScript.DefinitelyTyped bower install angularAMD
مدلهای برنامه:
public class BaseEntity { public int Id { get; set; } public bool Status { get; set; } public DateTime CreatedDateTime { get; set; } }
public class Ad : BaseEntity { public string Title { get; set; } public float Price { get; set; } public double Rating { get; set; } public int? RatingNumber { get; set; } public string UserId { get; set; } public DateTime ModifieDateTime { get; set; } public string Description { get; set; } public virtual ICollection<Comment> Comments { get; set; } public virtual IdentityUser User { get; set; } public virtual ICollection<AdLabel> Labels { get; set; } public virtual ICollection<AdMedia> Medias { get; set; } }
public class Label { public int Id { get; set; } public string Title { get; set; } public int? ParentId { get; set; } public virtual Label Parent { get; set; } public virtual ICollection<Label> Items { get; set; } }
public class Media { public int Id { get; set; } public string Name { get; set; } public string MimeType { get; set; } }
public class AdLabel { public int Id { get; set; } public virtual Ad Ad { get; set; } public virtual Label Label { get; set; } [Index("IX_AdLabel", 1, IsUnique = true)] public int AdId { get; set; } [Index("IX_AdLabel", 2, IsUnique = true)] public int LabelId { get; set; } public string Value { get; set; } }
public class AdMedia { public int Id { get; set; } public virtual Ad Ad { get; set; } public virtual Media Media { get; set; } [Index("IX_AdMedia", 1, IsUnique = true)] public int AdId { get; set; } [Index("IX_AdMedia", 2, IsUnique = true)] public int MediaId { get; set; } }
public class Comment : BaseEntity { public string Body { get; set; } public double Rating { get; set; } public int? RatingNumber { get; set; } public string EntityName { get; set; } public string UserId { get; set; } public int? ParentId { get; set; } public int? AdId { get; set; } public virtual Comment Parent { get; set; } public virtual Ad Ad { get; set; } public virtual ICollection<Comment> Items { get; set; } public virtual IdentityUser User { get; set; } }
public class Customer:BaseEntity { public string UserId { get; set; } public virtual string DisplayName { get; set; } public virtual string BirthDay { get; set; } public string City { get; set; } public string Address { get; set; } public int? MediaId { get; set; } public bool? NewsLetterSubscription { get; set; } public string PhoneNumber { get; set; } public virtual IdentityUser User { get; set; } public virtual Media Media { get; set; } }
public class Rating { public int Id { get; set; } public string UserId { get; set; } public Double Rate { get; set; } public string EntityName { get; set; } public int DestinationId { get; set; } }
اضافه کردن مدلهای برنامه به ApplicationDbContext
public class ApplicationDbContext : IdentityDbContext<ApplicationUser> { public ApplicationDbContext() : base("DefaultConnection", throwIfV1Schema: false) { } public DbSet<Ad> Ads { get; set; } public DbSet<AdLabel> AdLabels { get; set; } public DbSet<AdMedia> AdMedias { get; set; } public DbSet<Comment> Comments { get; set; } public DbSet<Label> Labels { get; set; } public DbSet<Media> Medias { get; set; } public static ApplicationDbContext Create() { return new ApplicationDbContext(); } }
لود کردن فایل main.js در فایل layout.cshtml ترجیحا در انتهای body
<script src="~/Scripts/require.js" data-main="/app/main"></script>
ایجاد فایل main.ts
requirejs.config({ paths: { "app": "app", "angularAmd":"/Scripts/angularAmd", "angular": "/Scripts/angular", "bootstrap": "/Scripts/bootstrap", "angularRoute": "/Scripts/angular-route", "jquery": "/Scripts/jquery-2.2.2", }, waitSeconds: 0, shim: { "angular": { exports: "angular" }, "angularRoute": { deps: ["angular"] }, "bootstrap": { deps: ["jquery"] }, "app": { deps: ["bootstrap","angularRoute"] } } }); require(["app"]);
ایجاد فایل app.ts: کارهایی که در فایل app انجام دادهایم:
<body ng-controller="SecurityCtrl"> ... </body>
"use strict"; module AdApps { class SecurityCtrl { private $scope: Interfaces.IAdvertismentScope; constructor($scope: Interfaces.IAdvertismentScope) { // security check this.$scope = $scope; } } define(["angularAmd", "angular"], (angularAmd, ng) => { angularAmd = angularAmd.__proto__; var app = ng.module("AngularTypeScript", ['ngRoute']); var viewPath = "app/views/"; var controllerPath = "app/controller/"; app.config(['$routeProvider', $routeProvider => { $routeProvider .when("/", angularAmd.route({ templateUrl: viewPath + "home.html", controllerUrl: controllerPath + "home .js" })) .otherwise({ redirectTo: '/' }); } ]); app.controller('SecurityCtrl', ['$scope', SecurityCtrl]); return angularAmd.bootstrap(app); })}
حال مواقعی پیش میآید که نیاز داریم پیغام هایی با گرافیک و عبارات متفاوت نمایش دهیم . برای رفع این نیاز میتوانیم از پلاگین jQuery Impromptu استفاده کنیم . البته این پلاگین قابلیتهای دیگری هم دارد که در این مقاله با آنها آشنا میشویم .
از ویژگیهای این پلاگین میتوان حجم کم (حدود 11 کیلوبایت) و قدرت شخصی سازی بالا اشاره کرد .
طرز استفاده به این شکل است :
$.prompt( msg , options )
msg میتواند یک string یا یک شئ از states باشد . string ارسال شده میتواند شامل کدهای html باشد .
یک شئ states هم شامل مجموعه ای از وضعیتهای prompt است . برای مثال میتوان یک prompt ایجاد کرد که مثل یک Wizard شامل چند مرحله باشد .
options هم تنظیماتی است که میتوان مشخص کرد . تنظیماتی مثل : prefix,classes,persistent,timeout,...
msg :
گفتیم شئ states شامل وضعیتهای مختلف prompt است . هر وضعیت ( state ) میتواند شامل بخشهای زیر باشد :
- html : مقدار Html وضعیت
- buttons : یک شئ شامل متن و مقدار دکمه هایی که کاربر میتواند کلیک کند
- focus : ایندکس دکمهی focus شده در وضعیت
- submit : تابعی که زمانی که یکی از دکمههای وضعیت انتخاب شود فراخوانی میشود .
اگر در این تابع false بازگشت داده شود یا متد preventDefault از event فراخوانی شود ، prompt باز میماند . ( روشی برای جلوگیری از بسته شدن prompt هنگام تغییر state یا اعتبار سنجی فرم )
همچنین شئ event شامل state ( المنت state ) و stateName ( نام state ) میباشد .
پیشفرض :
function(event, value, message, formVals){}
- position : مشخص کنندهی موقعیت state که شامل موارد زیر است :
position: { container: '#container', x: 0, y: 0, width: 0, arrow: 'lm' }
container : selector المنتی است که state باید در آن مکان قرار بگیرد .
x/y : موقعیت نسبی prompt نسبت به container
arrow : جهت نمایش فلش prompt است که میتواند یکی از این مقادیر باشد : tl, tc, tr, rt, tm, tb, br, bc, bl, lb, lm, lt.
var tourSubmitFunc = function (e, v, m, f) { if (v === -1) { $.prompt.prevState(); return false; } else if (v === 1) { $.prompt.nextState(); return false; } }; var states = { state0: { html: "State1", buttons: { Next: 1 }, //position: { container: '#container', x: 10, y: 0, width: 350, arrow: 'lm' }, submit: tourSubmitFunc }, state1: { html: "State2", buttons: { Prev: -1, Next: 1 }, submit: tourSubmitFunc }, state2: { html: "State3", buttons: { Prev: -1, Done: 0 }, submit: tourSubmitFunc } }; $.prompt(states);
تا به اینجا با پارامتر اول prompt آشنا شدیم و فهمیدیم که میتوانیم یک رشته یا یک شئ states به عنوان message به prompt ارسال کنیم .
options :
اکنون با optionهای prompt ( پارامتر دوم ) آشنا خواهیم شد .
توجه کنید که زمانی که یک رشته به prompt ارسال کنید ، مقادیر buttons,focus,submit از این تنظیمات دریافت میشود .
به عبارت دیگر ، زمانی که یک شئ states به prompt ارسال کنید ، از مقادیر فوق که در تنظیمات است ، استفاده نمیشود .
- loaded
یک تابع که زمانی که prompt کامل بارگزاری شده فراخوانی میشود .
$.prompt("Message", { loaded: function() { alert("Prompt Loaded !"); } });
- submit
یک تابع که زمانی که یکی از دکمههای state کلیک شود ، فراخوانی میشود .
( زمانی اتفاق میوفتد که یک رشته به عنوان متن به prompt ارسال کرده باشید و زمانی که یک شئ از states ارسال میکنید ، هنگام کلیک دکمههای آنها ، این تابع فراخوانی نمیشود . )
پیشفرض :
function(event){}
- statechanging
یک تابع که زمانی که یک state در حال تعویض شدن هست فراخوانی میشود .
پیشفرض :
function(event, fromStateName, toStateName){}
- statechanged
یک تابع که زمانی که یک state در حال تعویض شدن هست فراخوانی میشود .
پیشفرض :
function(event, toStateName){}
- callback
یک تابع که زمانی که ( یکی از دکمههای prompt کلیک شود و ) prompt بسته شود ، فراخوانی میشود .
پیشفرض :
function(event[, value, message, formVals]){}
- buttons
یک شئ شامل مجموعه ای از دکمهها .
پیشفرض :
{ Ok : true }
[ {title: 'Hello World',value:true}, {title: 'Good Bye',value:false} ]
- prefix
یک پیشوند برای همه css classها و idهای المنتهای html که توسط prompt ایجاد میشود .
پیشفرض : jqi
- classes
یک css class که به بالاترین سطح prompt داده میشود .
در حالت پیشفرض مقداری ندارد .
- focus
ایندکس دکمهی focus شده
پیشفرض : 0
- zIndex
zIndex اعمال شده بروی prompt .
پیشفرض : 999
- useiframe
استفاده از یک iframe برای overlay در IE6
پیشفرض : false
- top
فاصلهی prompt از بالای صفحه
پیشفرض : 15%
- opacity
میزان شفافیت لایهی ای که صفحه را پوشانده است .
پیشفرض : 0.6
- overlayspeed
سرعت نمایش افکت fadeIn , fadeOut لایهی پوشاننده .
مقادیر قابل قبول : "slow", "fast", number(milliseconds)
پیشفرض : "slow"
- promptspeed
سرعت نمایش prompt .
مقادیر قابل قبول : "slow", "fast", number(milliseconds)
پیشفرض : "fast"
- show
نام یک متد jQuery برای animate کردن نمایش prompt .
مقادیر قابل قبول : "show","fadeIn","slideDown", ...
پیشفرض : "promptDropIn"
- persistent
بسته شدن prompt زمانی که بروی لایهی fade کلیک شود .
false : بسته شدن
پیشفرض : true
- timeout
مدت زمانی که پس از آن ، prompt بصورت خودکار بسته میشود . ( milliseconds )
پیشفرض : 0
returns :
مقدار بازگشتی متد prompt ، یک شئ jQuery ، شامل همهی محتویات تولید شده توسط prompt است .
Events using Bind :
- promptloaded
معادل loaded در optionها .
- promptsubmit
هنگام submit شدن ( کلیک شدن یکی از دکمههای ) state فعال میشود .
- promptclose
معادل callback در optionها .
- promptstatechanging
معادل statechanging در optionها .
- promptstatechanged
معادل statechanged در optionها .
ظرز بایند کردن یک event به شئ prompt :
var myPrompt = $.prompt( msg , options ); myPrompt.bind('promptloaded', function(e){});
- jQuery.prompt.setDefaults(options)
تعیین مقادیر پیشفرض برای همهی promptها .
jQuery.prompt.setDefaults({ prefix: 'myPrompt', show: 'slideDown' });
- jQuery.prompt.setStateDefaults(options)
تعیین مقادیر پیشفرض برای stateها .
jQuery.prompt.setStateDefaults({ buttons: { Ok:true, Cancel:false }, focus: 1 });
- jQuery.prompt.getCurrentState()
یک شئ jQuery از state جاری برمیگرداند .
- jQuery.prompt.getCurrentStateName()
نام state جاری را برمیگرداند .
- jQuery.prompt.getStateContent(stateName)
یک شئ jQuery از state مشخص شده برمیگرداند .
- jQuery.prompt.goToState(stateName, callback)
state مشخص شده را در prompt نمایش میدهد .
callback تابعی است که بعد از تغییر state فراخوانی میشود .
- jQuery.prompt.nextState(callback)
prompt را به state بعدی منتقل میکند .
- jQuery.prompt.prevState(callback)
prompt را به state قبلی منتقل میکند .
- jQuery.prompt.close()
prompt را میبندد .
حال که با این پلاگین آشنا شدیم ، سه دستور جاوا اسکریپتی که در ابتدای مقاله ذکر کردیم را با این پلاگین پیاده سازی میکنیم .
- alert
$.prompt("یک پیام تستی", { prefix: 'dnt', buttons: { 'تایید': true } });
نتیجه :
- confirm
$.prompt("درخواست تایید - موافقید ؟", { prefix: 'dnt', buttons: { 'تایید': true, 'انصراف': false } });
نتیجه :
- prompt
یک فرم html مخفی برای نمایش در prompt :
<div class="prompt-content" style="display: none;"> <span>نام خود را وارد نمایید : </span> <span> <input type="text" name="name" /> </span> </div>
نمایش prompt :
$.prompt( $(".prompt-content").html(), { prefix: 'dnt', buttons: { 'تایید': true, 'انصراف': false } });
نتیجه :
در این سه مثال آخر ، از یک css متفاوت استفاده کردیم . این پلاگین یک سری کلاس دارد که نام این کلاسها از ترکیب مقدار prefix که در option مشخص کردیم حاصل میشود .
div.dnt .dntmessage { color: #444444; line-height: 20px; padding: 10px; /* Edited */ direction:rtl; text-align:right; }
البته راه بهتری هم هست که نیاز به آشنایی با فایرباگ دارد . در این روش ابتدا کل قالب jqi ( موجود در قالب پیشفرض ) را در برنامه خود کپی میکنیم ، مقادیر jqi را با نام قالب جایگزین میکنیم ، مقدار prefix را در prompt برابر با نام قالب قرار میهیم .
اکنون در FireFox یک prompt ایجاد میکنیم و توسط فایرباگ استایل هایی که با نام قالب بروی prompt اعمال شدهاند را مطابق سلیقه تغییر میدهیم . در مرحله آخر به تب CSS در فایرباگ میرویم و کل استایلهای مربوط به قالب را کپی و جایگزین استایل قبلی در برنامه میکنیم .
/* Start : DotNetTips Theme */ .dntfade { background-color: #AAAAAA; position: absolute; } div.dnt { background-color: #FFFFFF; border-radius: 10px 10px 10px 10px; border: 1px solid #FFFFFF; box-shadow: 0px 0px 10px 1px #6D6D6C; font-family: tahoma; font-size: 11px; padding: 7px; position: absolute; text-align: left; width: 400px; } div.dnt .dntcontainer { font-size: small; } div.dnt .dntclose { color: #BBBBBB; cursor: pointer; font-weight: bold; position: absolute; top: 4px; width: 18px; } div.dnt .dntmessage { color: #444444; line-height: 20px; padding: 10px; } div.dnt .dntbuttons { background-color: #F4F4F4; border: 1px solid #EEEEEE; padding: 5px 0px; text-align: right; } div.dnt button { background-color: #2F6073; border: 1px solid #F4F4F4; color: #FFFFFF; font-size: 12px; font-weight: bold; margin: 0px 10px; padding: 3px 10px; } div.dnt button:hover { background-color: #728A8C; } div.dnt button.dntdefaultbutton { background-color: #0099CC; } .dnt_state { direction: rtl; text-align: right; } .dnt_state button { font-family: tahoma; } .dntwarning .dnt .dntbuttons { background-color: #CCDDFF; } .dnt .dntarrow { border: 10px solid transparent; font-size: 0px; height: 0px; line-height: 0; position: absolute; width: 0px; } .dnt .dntarrowtl { border-bottom-color: #FFFFFF; left: 10px; top: -20px; } .dnt .dntarrowtc { border-bottom-color: #FFFFFF; left: 50%; margin-left: -10px; top: -20px; } .dnt .dntarrowtr { border-bottom-color: #FFFFFF; right: 10px; top: -20px; } .dnt .dntarrowbl { border-top-color: #FFFFFF; bottom: -20px; left: 10px; } .dnt .dntarrowbc { border-top-color: #FFFFFF; bottom: -20px; left: 50%; margin-left: -10px; } .dnt .dntarrowbr { border-top-color: #FFFFFF; bottom: -20px; right: 10px; } .dnt .dntarrowlt { border-right-color: #FFFFFF; left: -20px; top: 10px; } .dnt .dntarrowlm { border-right-color: #FFFFFF; left: -20px; margin-top: -10px; top: 50%; } .dnt .dntarrowlb { border-right-color: #FFFFFF; bottom: 10px; left: -20px; } .dnt .dntarrowrt { border-left-color: #FFFFFF; right: -20px; top: 10px; } .dnt .dntarrowrm { border-left-color: #FFFFFF; margin-top: -10px; right: -20px; top: 50%; } .dnt .dntarrowrb { border-left-color: #FFFFFF; bottom: 10px; right: -20px; } /* End : DotNetTips Theme */
امکان ساخت قالب برای پروژههای NET Core.
dotnet new -u <NUGET_PACKAGE_ID> dotnet new -u <ABSOLUTE_Path to template.config folder>