public double TotalRating { get ; set ; } = 0.0 ; public int TotalRaters { get ; set ; } = 0 ; public double AverageRating { get ; set ; } = 0.0 ;
modelBuilder.Entity<Product>().OwnsOne(p = > p.Rating)
public double TotalRating { get ; set ; } = 0.0 ; public int TotalRaters { get ; set ; } = 0 ; public double AverageRating { get ; set ; } = 0.0 ;
modelBuilder.Entity<Product>().OwnsOne(p = > p.Rating)
public virtual User User { get; set; } public virtual Role Role { get; set; }
public virtual ICollection<UserRole> UserRoles { get; set; } = new HashSet<UserRole>();
@Number @code { [Parameter] public string Number { get; set; } protected override Task OnInitializedAsync() { var persianDic = new Dictionary<char, char> { {'0','۰'}, {'1','۱'}, {'2','۲'}, {'3','۳'}, {'4','۴'}, {'5','۵'}, {'6','۶'}, {'7','۷'}, {'8','۸'}, {'9','۹'}, }; var number = Number.ToString(); var ech = number.ToCharArray(); for (int i = 0; i < ech.Length; i++) { persianDic.TryGetValue(ech[i], out char pch); if (pch == null) continue; ech[i] = pch; } Number = new string(ech); return base.OnInitializedAsync(); } }
... @foreach (var item in _items) { <tr> <td class="h6 text-color-1">@item.Title</td> <td> <PersianNumber Number="@item.Price.ToString()"/> ریال</td> </tr> } ...
protected void btnGetData_Click(object sender, EventArgs e)
{
lblResult.Text = (Math.PI * double.Parse(txtRadius.Text) * double.Parse(txtRadius.Text)).ToString();
}
using System;
namespace MVPTest
{
public interface ICircleModel
{
double GetArea(double radius);
}
public class CModel : ICircleModel
{
public double GetArea(double radius)
{
return Math.PI * radius * radius;
}
}
}
namespace MVPTest
{
public interface IView
{
string RadiusText { get; set; }
string ResultText { get; set; }
}
}
namespace MVPTest
{
public class CPresenter
{
IView _view;
public CPresenter(IView view)
{
_view = view;
}
public void CalculateCircleArea()
{
CModel model = new CModel();
_view.ResultText = model.GetArea(double.Parse(_view.RadiusText)).ToString();
}
}
}
using System;
namespace MVPTest
{
public partial class _Default : System.Web.UI.Page, IView
{
protected void Page_Load(object sender, EventArgs e)
{
}
public string RadiusText
{
get { return txtRadius.Text; }
set { txtRadius.Text = value; }
}
public string ResultText
{
get { return lblResult.Text; }
set { lblResult.Text = value; }
}
protected void btnGetData_Click(object sender, EventArgs e)
{
CPresenter presenter = new CPresenter(this);
presenter.CalculateCircleArea();
}
}
}
public class MyHttpHandler : IHttpHandler { public void ProcessRequest(HttpContext context) { } public bool IsReusable { get { return false; } } }
public class MyHttpHandler : IHttpHandler { public void ProcessRequest(HttpContext context) { HttpResponse response = context.Response; HttpRequest request = context.Request; response.Write("Every Page has a some text like this"); } public bool IsReusable { get { return false; } } }
<system.web> <httpHandlers> <add verb="*" path="*.aspx" type="MyHttpHandler"/> </httpHandlers> </system.web>
<configuration> <system.web> <httpHandlers> <add name="myhttphandler" verb="*" path="*.aspx" type="MyHttpHandler"/> </httpHandlers> </system.web> </configuration>
گزینه Type که نام کلاس میباشد و اگر کلاس داخل یک فضای نام قرار گرفته باشد، باید اینطور نوشت : namespace.ClassName |
گزینه verb شامل مقادیری چون Get,Post,Head,Putو Delete میباشد و httphandler را فقط برای این نوع درخواستها اجرا میکند و در صورتیکه بخواهید چندتا از آنها را استفاده کنید، با , از هم جدا میشوند. مثلا Get,post و درصورتیکه همهی گزینهها را بخواهید علامت * را میتوان استفاده کرد. |
گزینهی path این امکان را به شما میدهد که مسیر و نوع فایلهایی را که قصد دارید روی آنها فقط اجرا شود، مشخص کنید و ما در قطعه کد بالا گفتهایم که تنها روی فایلهایی با پسوند aspx اجرا شود و چون مسیری هم ذکر نکردیم برای همهی مسیرها قابل اجراست. یکی از مزیتهای دادن پسوند این است که میتوانید پسوندهای اختصاصی داشته باشید. مثلا پسوند RSS برای فیدهای وب سایتتان. بسیاری از برنامه نویسان به جای استفاده از صفحات aspx از ashx استفاده میکنند که به مراتب سبکتر از aspx هست و شامل بخش ui نمیشود و نتیجه خروجی آن بر اساس کدی که مینویسید مشخص میشود که میتواند صفحه متنی یا عکس یا xml یا ... باشد. در اینجا در مورد ساخت صفحات ashx توضیح داده شده است. |
public class MyHttpHandler1 :IHttpHandler { public void ProcessRequest(HttpContext context) { HttpResponse response = context.Response; response.Write("this is httphandler1"); } public bool IsReusable { get { return false; } } } public class MyHttpHandler2 : IHttpHandler { public void ProcessRequest(HttpContext context) { HttpResponse response = context.Response; response.Write("this is httphandler2"); } public bool IsReusable { get { return false; } } }
public class MyFactory : IHttpHandlerFactory { public IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTrasnlated) { } public void ReleaseHandler(IHttpHandler handler) { } }
Context | یک شی از کلاس httpcontext که دسترسی ما را برای اشیاء سروری چون response,request,session و... فراهم میکند. |
RequestType | مشخص میکند که درخواست صفحه به چه صورتی است. این گزینه برای مواردی است که verb بیش از یک مورد را حمایت میکند. برای مثال دوست دارید یک هندلر را برای درخواستهای Get ارسال کنید و هندلر دیگر را برای درخواستهای نوع Post |
URL | مسیر مجازی virtual Path صفحه صدا زده شده |
PathTranslated | مسیر فیزیکی صفحه درخواست کننده را ارسال میکند. |
public IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTrasnlated) { string handlername = "MyHttpHandler1"; if(url.Substring(url.LastIndexOf("/")+1).StartsWith("t")) { handlername = "MyHttpHandler2"; } try { return (IHttpHandler) Activator.CreateInstance(Type.GetType(handlername)); } catch (Exception e) { throw new HttpException("Error: " + handlername, e); } } public void ReleaseHandler(IHttpHandler handler) { } }
موقعی که اینترفیس IHttpAsyncHandler را ارث بری کنید (این اینترفیس نیز از IHttpHandler ارث بری کرده است و دو متد اضافهتر دارد)، باید دو متد دیگر را نیز پیاده سازی کنید:در اعمالی که disk I/O و یا network I/O دارند، پردازش موازی و اعمال async به شدت مقیاس پذیری سیستم را بالا میبرند. به این ترتیب worker thread جاری (که تعداد آنها محدود است)، سریعتر آزاد شده و به worker pool بازگشت داده میشود تا بتواند به یک درخواست دیگر رسیده سرویس دهد. در این حالت میتوان با منابع کمتری، درخواستهای بیشتری را پردازش کرد.
public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback callback, object obj) { } public void EndProcessRequest(IAsyncResult result) { }
public class AsynchOperation : IAsyncResult { private bool _completed; private Object _state; private AsyncCallback _callback; private HttpContext _context; bool IAsyncResult.IsCompleted { get { return _completed; } } WaitHandle IAsyncResult.AsyncWaitHandle { get { return null; } } Object IAsyncResult.AsyncState { get { return _state; } } bool IAsyncResult.CompletedSynchronously { get { return false; } } }
public AsynchOperation(AsyncCallback callback, HttpContext context, Object state) { _callback = callback; _context = context; _state = state; _completed = false; }
public void StartAsyncWork() { ThreadPool.QueueUserWorkItem(new WaitCallback(StartAsyncTask),null); }
private void StartAsyncTask(Object workItemState) { _context.Response.Write("<p>Completion IsThreadPoolThread is " + Thread.CurrentThread.IsThreadPoolThread + "</p>\r\n"); _context.Response.Write("Hello World from Async Handler!"); _completed = true; _callback(this); }
context.Response.Write("<p>Begin IsThreadPoolThread is " + Thread.CurrentThread.IsThreadPoolThread + "</p>\r\n"); AsynchOperation asynch = new AsynchOperation(callback, context, obj); asynch.StartAsyncWork(); return asynch;
public class MyHttpHandler : IHttpAsyncHandler { public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback callback, object obj) { context.Response.Write("<p>Begin IsThreadPoolThread is " + Thread.CurrentThread.IsThreadPoolThread + "</p>\r\n"); AsynchOperation asynch = new AsynchOperation(callback, context, obj); asynch.StartAsyncWork(); return asynch; } public void EndProcessRequest(IAsyncResult result) { } public void ProcessRequest(HttpContext context) { throw new InvalidOperationException(); } public bool IsReusable { get { return false; } } } public class AsynchOperation : IAsyncResult { private bool _completed; private Object _state; private AsyncCallback _callback; private HttpContext _context; bool IAsyncResult.IsCompleted { get { return _completed; } } WaitHandle IAsyncResult.AsyncWaitHandle { get { return null; } } Object IAsyncResult.AsyncState { get { return _state; } } bool IAsyncResult.CompletedSynchronously { get { return false; } } public AsynchOperation(AsyncCallback callback, HttpContext context, Object state) { _callback = callback; _context = context; _state = state; _completed = false; } public void StartAsyncWork() { ThreadPool.QueueUserWorkItem(new WaitCallback(StartAsyncTask),null); } private void StartAsyncTask(Object workItemState) { _context.Response.Write("<p>Completion IsThreadPoolThread is " + Thread.CurrentThread.IsThreadPoolThread + "</p>\r\n"); _context.Response.Write("Hello World from Async Handler!"); _completed = true; _callback(this); }
مایکروسافت در MSDN نوشته است که httphandlerها در واقع فرآیندهایی هستند (به این فرایندها بیشتر End Point میگویند) که در پاسخ به درخواستهای رسیده شده توسط asp.net application اجرا میشوند و بیشترین درخواست هایی هم که میرسد از نوع صفحات Aspx میباشد و موقعی که کاربری درخواست صفحهی aspx میکند هندلرهای مربوط به page اجرا میشوند.
var ms = new MemoryStream(); using (var writer = XmlWriter.Create(ms)) { EdmxWriter.WriteEdmx(new Context(), writer); }
var xDoc = XDocument.Load(ms); var ssdl = xDoc.Descendants("{http://schemas.microsoft.com/ado/2009/02/edm/ssdl}Schema").Single(); var csdl = xDoc.Descendants("{http://schemas.microsoft.com/ado/2008/09/edm}Schema").Single(); var msl = xDoc.Descendants("{http://schemas.microsoft.com/ado/2008/09/mapping/cs}Mapping").Single();
EdmGen.exe /mode:ViewGeneration /incsdl:Context.csdl /inmsl:Context.msl /inssdl:Context.ssdl /outviews:Context.Views.cs
using System; using System.Data.Entity; using System.Data.Entity.Design; using System.Data.Entity.Infrastructure; using System.Data.Mapping; using System.Data.Metadata.Edm; using System.IO; using System.Linq; using System.Xml; using System.Xml.Linq; namespace EfUtils { public static class PreGeneratedViewsWriter { public static void CreatePreGeneratedViewsFile( this DbContext contextInstance, LanguageOption language = LanguageOption.GenerateCSharpCode, string viewsFile = "Context.Views.cs", string edmxFile = "context.edmx", string ssdlFile = "context.ssdl.xml", string csdlFile = "context.csdl.xml", string mslFile = "context.msl.xml") { using (var contextViewsMemoryStream = new MemoryStream()) { using (var edmxMemoryStream = new MemoryStream()) { var edmx = createEdmx(contextInstance, edmxFile, edmxMemoryStream); var mappingItemCollection = createMappingItemCollection(ssdlFile, csdlFile, mslFile, edmx); generateViews(language, viewsFile, contextViewsMemoryStream, mappingItemCollection); } } } private static void generateViews(LanguageOption language, string viewsFile, MemoryStream contextViewsMemoryStream, StorageMappingItemCollection mappingItemCollection) { var viewGenerator = new EntityViewGenerator // It's defined in System.Data.Entity.Design.dll { LanguageOption = language }; using (var streamWriter = new StreamWriter(contextViewsMemoryStream)) { var errors = viewGenerator.GenerateViews(mappingItemCollection, streamWriter).ToList(); if (errors.Any()) throw new InvalidOperationException(errors.First().Message); contextViewsMemoryStream.Position = 0; using (var reader = new StreamReader(contextViewsMemoryStream)) { var codeData = reader.ReadToEnd(); File.WriteAllText(viewsFile, codeData); } } } private static StorageMappingItemCollection createMappingItemCollection(string ssdlFile, string csdlFile, string mslFile, XDocument edmx) { var ssdl = edmx.Descendants("{http://schemas.microsoft.com/ado/2009/02/edm/ssdl}Schema").Single(); ssdl.Save(ssdlFile); var storeItemCollection = new StoreItemCollection(new[] { ssdl.CreateReader() }); var csdl = edmx.Descendants("{http://schemas.microsoft.com/ado/2008/09/edm}Schema").Single(); csdl.Save(csdlFile); var edmItemCollection = new EdmItemCollection(new[] { csdl.CreateReader() }); var msl = edmx.Descendants("{http://schemas.microsoft.com/ado/2008/09/mapping/cs}Mapping").Single(); msl.Save(mslFile); var mappingItemCollection = new StorageMappingItemCollection(edmItemCollection, storeItemCollection, new[] { msl.CreateReader() }); return mappingItemCollection; } private static XDocument createEdmx(DbContext contextInstance, string edmxFile, MemoryStream edmxMemoryStream) { var settings = new XmlWriterSettings { Indent = true }; using (var writer = XmlWriter.Create(edmxMemoryStream, settings)) { EdmxWriter.WriteEdmx(contextInstance, writer); } File.WriteAllBytes(edmxFile, edmxMemoryStream.ToArray()); edmxMemoryStream.Position = 0; var edmx = XDocument.Load(edmxMemoryStream); return edmx; } } }
Database.SetInitializer<MyContext>(null);
استفاده از Exception برای نمایش پیغام برای کاربر نهایی
با صدور یک استثناء و مدیریت سراسری آن در بالاترین (خارجی ترین) لایه و نمایش پیغام مرتبط با آن به کاربر نهایی، میتوان از آن به عنوان ابزاری برای ارسال هر نوع پیغامی به کاربر نهایی استفاده کرد. اگر قوانین تجاری با موفقیت برآورده نشدهاند یا لازم است به هر دلیلی یک پیغام مرتبط با یک اعتبارسنجی تجاری را برای کاربر نمایش دهید، این روش بسیار کارساز میباشد و با یکبار وقت گذاشتن برای توسعه زیرساخت برای این موضوع، به عنوان یک Cross Cutting Concern تحت عنوان Exception Management، آزادی عمل زیادی در ادامه توسعه سیستم خود خواهید داشت.
اگر مطالب پیش نیاز را مطالعه کنید، قطعا روش مطرح شده را انتخاب نخواهید کرد؛ به همین دلیل به دنبال راه حل صحیح برخورد با این سناریوها بودم که نتیجه آن را در ادامه خواهیم دید.
راه حل صحیح برای برخورد با این سناریوها بازگشت یک Result میباشد که در مطلب قبلی هم تحت عنوان OperationResult مطرح شد.
public class Result { private static readonly Result SuccessResult = new Result(true, null); protected Result(bool succeeded, string message) { if (succeeded) { if (message != null) throw new ArgumentException("There should be no error message for success.", nameof(message)); } else { if (message == null) throw new ArgumentNullException(nameof(message), "There must be error message for failure."); } Succeeded = succeeded; Error = message; } public bool Succeeded { get; } public string Error { get; } [DebuggerStepThrough] public static Result Success() { return SuccessResult; } [DebuggerStepThrough] public static Result Failed(string message) { return new Result(false, message); } [DebuggerStepThrough] public static Result<T> Failed<T>(string message) { return new Result<T>(default, false, message); } [DebuggerStepThrough] public static Result<T> Success<T>(T value) { return new Result<T>(value, true, string.Empty); } [DebuggerStepThrough] public static Result Combine(string seperator, params Result[] results) { var failedResults = results.Where(x => !x.Succeeded).ToList(); if (!failedResults.Any()) return Success(); var error = string.Join(seperator, failedResults.Select(x => x.Error).ToArray()); return Failed(error); } [DebuggerStepThrough] public static Result Combine(params Result[] results) { return Combine(", ", results); } [DebuggerStepThrough] public static Result Combine<T>(params Result<T>[] results) { return Combine(", ", results); } [DebuggerStepThrough] public static Result Combine<T>(string seperator, params Result<T>[] results) { var untyped = results.Select(result => (Result) result).ToArray(); return Combine(seperator, untyped); } public override string ToString() { return Succeeded ? "Succeeded" : $"Failed : {Error}"; } }
مشابه کلاس بالا، در فریمورک ASP.NET Identity کلاسی تحت عنوان IdentityResult برای همین منظور در نظر گرفته شدهاست.
پراپرتی Succeeded نشان دهنده موفقت آمیز بودن یا عدم موفقیت عملیات (به عنوان مثال یک متد ApplicationService) میباشد. پراپرتی Error دربرگیرنده پیغام خطایی میباشد که قبلا از طریق Message مربوط به یک استثناء صادر شده، در اختیار بالاترین لایه قرار میگرفت. با استفاده از متد Combine، امکان ترکیب چندین Result حاصل از عملیات مختلف را خواهید داشت. متدهای استاتیک Failed و Success هم برای درگیر نشدن برای وهله سازی از کلاس Result در نظر گرفته شدهاند.
متد GetForEdit مربوط به MeetingService را در نظر بگیرید. به عنوان مثال وظیفه این متد بازگشت یک MeetingEditModel میباشد؛ اما با توجه به یکسری قواعد تجاری، بهعنوان مثال «امکان ویرایش جلسهای که پابلیش نهایی شدهاست، وجود ندارد و ...» لازم است خروجی این متد نیز در صورت Fail شدن، دلیل آن را به مصرف کننده ارائه دهد. از این رو کلاس جنریک Result را به شکل زیر خواهیم داشت:
public class Result<T> : Result { private readonly T _value; protected internal Result(T value, bool succeeded, string error) : base(succeeded, error) { _value = value; } public T Value { get { if (!Succeeded) throw new InvalidOperationException("There is no value for failure."); return _value; } } }
public static class ResultExtensions { public static Result<TK> OnSuccess<T, TK>(this Result<T> result, Func<T, TK> func) { return !result.Succeeded ? Result.Failed<TK>(result.Error) : Result.Success(func(result.Value)); } public static Result<T> Ensure<T>(this Result<T> result, Func<T, bool> predicate, string message) { if (!result.Succeeded) return Result.Failed<T>(result.Error); return !predicate(result.Value) ? Result.Failed<T>(message) : Result.Success(result.Value); } public static Result<TK> Map<T, TK>(this Result<T> result, Func<T, TK> func) { return !result.Succeeded ? Result.Failed<TK>(result.Error) : Result.Success(func(result.Value)); } public static Result<T> OnSuccess<T>(this Result<T> result, Action<T> action) { if (result.Succeeded) action(result.Value); return result; } public static T OnBoth<T>(this Result result, Func<Result, T> func) { return func(result); } public static Result OnSuccess(this Result result, Action action) { if (result.Succeeded) action(); return result; } public static Result<T> OnSuccess<T>(this Result result, Func<T> func) { return !result.Succeeded ? Result.Failed<T>(result.Error) : Result.Success(func()); } public static Result<TK> OnSuccess<T, TK>(this Result<T> result, Func<T, Result<TK>> func) { return !result.Succeeded ? Result.Failed<TK>(result.Error) : func(result.Value); } public static Result<T> OnSuccess<T>(this Result result, Func<Result<T>> func) { return !result.Succeeded ? Result.Failed<T>(result.Error) : func(); } public static Result<TK> OnSuccess<T, TK>(this Result<T> result, Func<Result<TK>> func) { return !result.Succeeded ? Result.Failed<TK>(result.Error) : func(); } public static Result OnSuccess<T>(this Result<T> result, Func<T, Result> func) { return !result.Succeeded ? Result.Failed(result.Error) : func(result.Value); } public static Result OnSuccess(this Result result, Func<Result> func) { return !result.Succeeded ? result : func(); } public static Result Ensure(this Result result, Func<bool> predicate, string message) { if (!result.Succeeded) return Result.Failed(result.Error); return !predicate() ? Result.Failed(message) : Result.Success(); } public static Result<T> Map<T>(this Result result, Func<T> func) { return !result.Succeeded ? Result.Failed<T>(result.Error) : Result.Success(func()); } public static TK OnBoth<T, TK>(this Result<T> result, Func<Result<T>, TK> func) { return func(result); } public static Result<T> OnFailure<T>(this Result<T> result, Action action) { if (!result.Succeeded) action(); return result; } public static Result OnFailure(this Result result, Action action) { if (!result.Succeeded) action(); return result; } public static Result<T> OnFailure<T>(this Result<T> result, Action<string> action) { if (!result.Succeeded) action(result.Error); return result; } public static Result OnFailure(this Result result, Action<string> action) { if (!result.Succeeded) action(result.Error); return result; } }
[HttpPost, AjaxOnly, ValidateAntiForgeryToken, ValidateModelState] public virtual async Task<ActionResult> Create([Bind(Prefix = "Model")]MeetingCreateModel model) { var result = await _service.CreateAsync(model); return result.OnSuccess(() => { }) .OnFailure(() => { }) .OnBoth(r => r.Succeeded ? InformationNotification("Messages.Save.Success") : ErrorMessage(r.Error)); }
یا در حالتهای پیچیده تر:
var result = await _service.CreateAsync(new TenantAwareEntityCreateModel()); return Result.Combine(result, Result.Success(), Result.Failed("نتیجه یک متد دیگر به عنوان مثال")) .OnSuccess(() => { }) .OnFailure(() => { }) .OnBoth(r => r.Succeeded ? Json("OK") : Json(r.Error));
ترکیب با الگوی Maybe یا Option
public struct Maybe<T> : IEquatable<Maybe<T>> where T : class { private readonly T _value; private Maybe(T value) { _value = value; } public bool HasValue => _value != null; public T Value => _value ?? throw new InvalidOperationException(); public static Maybe<T> None => new Maybe<T>(); public static implicit operator Maybe<T>(T value) { return new Maybe<T>(value); } public static bool operator ==(Maybe<T> maybe, T value) { return maybe.HasValue && maybe.Value.Equals(value); } public static bool operator !=(Maybe<T> maybe, T value) { return !(maybe == value); } public static bool operator ==(Maybe<T> left, Maybe<T> right) { return left.Equals(right); } public static bool operator !=(Maybe<T> left, Maybe<T> right) { return !(left == right); } /// <inheritdoc /> /// <summary> /// Avoid boxing and Give type safety /// </summary> /// <param name="other"></param> /// <returns></returns> public bool Equals(Maybe<T> other) { if (!HasValue && !other.HasValue) return true; if (!HasValue || !other.HasValue) return false; return _value.Equals(other.Value); } /// <summary> /// Avoid reflection /// </summary> /// <param name="obj"></param> /// <returns></returns> public override bool Equals(object obj) { if (obj is T typed) { obj = new Maybe<T>(typed); } if (!(obj is Maybe<T> other)) return false; return Equals(other); } /// <summary> /// Good practice when overriding Equals method. /// If x.Equals(y) then we must have x.GetHashCode()==y.GetHashCode() /// </summary> /// <returns></returns> public override int GetHashCode() { return HasValue ? _value.GetHashCode() : 0; } public override string ToString() { return HasValue ? _value.ToString() : "NO VALUE"; } }
public static Result<T> ToResult<T>(this Maybe<T> maybe, string message) where T : class { return !maybe.HasValue ? Result.Failed<T>(message) : Result.Success(maybe.Value); }
Result<Customer> customerResult = _customerRepository.GetById(model.Id) .ToResult("Customer with such Id is not found: " + model.Id);
همچنین متدهای الحاقی زیر را نیز برای ساختار داده Maybe میتوان در نظر گرفت:
public static T GetValueOrDefault<T>(this Maybe<T> maybe, T defaultValue = default) where T : class { return maybe.GetValueOrDefault(x => x, defaultValue); } public static TK GetValueOrDefault<T, TK>(this Maybe<T> maybe, Func<T, TK> selector, TK defaultValue = default) where T : class { return maybe.HasValue ? selector(maybe.Value) : defaultValue; } public static Maybe<T> Where<T>(this Maybe<T> maybe, Func<T, bool> predicate) where T : class { if (!maybe.HasValue) return default(T); return predicate(maybe.Value) ? maybe : default(T); } public static Maybe<TK> Select<T, TK>(this Maybe<T> maybe, Func<T, TK> selector) where T : class where TK : class { return !maybe.HasValue ? default : selector(maybe.Value); } public static Maybe<TK> Select<T, TK>(this Maybe<T> maybe, Func<T, Maybe<TK>> selector) where T : class where TK : class { return !maybe.HasValue ? default(TK) : selector(maybe.Value); } public static void Execute<T>(this Maybe<T> maybe, Action<T> action) where T : class { if (!maybe.HasValue) return; action(maybe.Value); } }
using System; namespace IndexedProperties { public class Data { private int[] _localArray; private ArrayIndexer _arrayIndexer; public Data() { _localArray = new int[10]; for (int i = 0; i < 10; i++) _localArray[i] = i + 1; _arrayIndexer = new ArrayIndexer(this); } public ArrayIndexer Number { get { return _arrayIndexer; } } public class ArrayIndexer { private Data _arrayOwner; public ArrayIndexer(Data arrayOwner) { _arrayOwner = arrayOwner; } public int this[int index] { get { return _arrayOwner._localArray[index]; } } public int Length { get { return _arrayOwner._localArray.Length; } } } } class Program { static void Main(string[] args) { var data = new Data(); for (int i = 0; i < 10; i++) Console.WriteLine(data.Number[i]); } } }
public class TextResult : ActionResult { public string FileName { get; set; } public override void ExecuteResult(ControllerContext context) { var filePath = Path.Combine(context.HttpContext.Server.MapPath(@"~/Files/"), FileName); var data = File.ReadAllText(filePath); context.HttpContext.Response.Write(data); } }
public ActionResult DownloadTextFile(string fileName) { return new TextResult { FileName = fileName }; }
public ActionResult DownloadTextFile(string fileName) { var filePath = Path.Combine(HttpContext.Server.MapPath(@"~/Files/"), fileName); return File(filePath, "text"); }
public class CsvActionResult : ActionResult { public IEnumerable ModelListing { get; set; } public CsvActionResult(IEnumerable modelListing) { ModelListing = modelListing; } public override void ExecuteResult(ControllerContext context) { byte[] data = new CsvFileCreator().AsBytes(ModelListing); var fileResult = new FileContentResult(data, "text/csv") { FileDownloadName = "CsvFile.csv" }; fileResult.ExecuteResult(context); } }
public ActionResult ExportUsers() { IEnumerable<User> model = UserRepository.GetUsers(); return new CsvActionResult(model); }
public class LogoutActionResult : ActionResult { public RedirectToRouteResult ActionAfterLogout { get; set; } public LogoutActionResult(RedirectToRouteResult actionAfterLogout) { ActionAfterLogout = actionAfterLogout; } public override void ExecuteResult(ControllerContext context) { FormsAuthentication.SignOut(); ActionAfterLogout.ExecuteResult(context); } }
public ActionResult Logout() { var redirect = RedirectToAction("Index", "Home"); return new LogoutActionResult(redirect); }
[TestMethod] public void The_Logout_Action_Returns_LogoutActionResult() { //arrange var account = new AccountController(); //act var result = account.Logout() as LogoutActionResult; //assert Assert.AreEqual(result.ActionAfterLogout.RouteValues["Controller"], "Home"); }
{ "Value": null }
public class StringJsonConverter : JsonConverter<byte?> { public override byte? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return reader.TokenType switch { JsonTokenType.Number => reader.GetByte(), JsonTokenType.Null => null, JsonTokenType.String => byte.TryParse(reader.GetString(), NumberStyles.Number, CultureInfo.InvariantCulture, out var parsed) ? parsed : (byte?)null, _ => throw new ArgumentOutOfRangeException(nameof(reader), reader.TokenType, "Cannot parse unexpected JSON token type.") }; } public override void Write(Utf8JsonWriter writer, byte? value, JsonSerializerOptions options) { if (value.HasValue) { writer.WriteNumberValue(value.Value); } else { writer.WriteNullValue(); } } }