برای عملکرد صحیح متد Distinct موجود در LINQ لازم است. یک روش پیاده سازی IEqualityComparer است به صورت مجزا و یا داخل همان کلاس هم میشود متدهای Equals و GetHashCode را قرار داد.
پاسخ به بازخوردهای پروژهها
namespace PluginsBase { public interface IPlugin { string Name { get; } void Run(); } }
using PluginsBase; namespace Plugin1 { public class Plugin1Main : IPlugin { public string Name { get { return "Test 1"; } } public void Run() { // todo: ... } } }
Copy "$(ProjectDir)$(OutDir)$(TargetName).*" "$(SolutionDir)WinFormsWithPluginSupport\bin\debug\Plugins"
Copy "$(ProjectDir)$(OutDir)*.*" "$(SolutionDir)WinFormsWithPluginSupport\bin\debug\Plugins"
PM> install-package structuremap
using System.IO; using System.Windows.Forms; using PluginsBase; using StructureMap.Configuration.DSL; using StructureMap.Graph; namespace WinFormsWithPluginSupport.Core { public class PluginsRegistry : Registry { public PluginsRegistry() { this.Scan(scanner => { scanner.AssembliesFromPath( path: Path.Combine(Application.StartupPath, "plugins"), // یک اسمبلی نباید دوبار بارگذاری شود assemblyFilter: assembly => { return !assembly.FullName.Equals(typeof(IPlugin).Assembly.FullName); }); scanner.AddAllTypesOf<IPlugin>().NameBy(item => item.FullName); }); } } }
using System; using System.Threading; using StructureMap; namespace WinFormsWithPluginSupport { public static class IocConfig { private static readonly Lazy<Container> _containerBuilder = new Lazy<Container>(defaultContainer, LazyThreadSafetyMode.ExecutionAndPublication); public static IContainer Container { get { return _containerBuilder.Value; } } private static Container defaultContainer() { return new Container(x => { x.AddRegistry<PluginsRegistry>(); }); } } }
using System.Windows.Forms; using StructureMap; namespace WinFormsWithPluginSupport { public partial class FrmMain : Form { private readonly IContainer _container; public FrmMain(IContainer container) { _container = container; InitializeComponent(); } } }
using System; using System.Windows.Forms; namespace WinFormsWithPluginSupport { static class Program { [STAThread] static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(IocConfig.Container.GetInstance<FrmMain>()); } } }
using System.Linq; using System.Windows.Forms; using PluginsBase; using StructureMap; using WinFormsWithPluginSupport.Core; namespace WinFormsWithPluginSupport { public partial class FrmMain : Form { private readonly IContainer _container; public FrmMain(IContainer container) { _container = container; InitializeComponent(); } private void BtnRun_Click(object sender, System.EventArgs e) { var plugins = _container.GetAllInstances<IPlugin>().ToList(); foreach (var plugin in plugins) { plugin.Run(); } } private void BtnReload_Click(object sender, System.EventArgs e) { _container.EjectAllInstancesOf<IPlugin>(); _container.Configure(x => x.AddRegistry<PluginsRegistry>() ); } } }
class Car { } class CarProducer { public void DeliverTo(int carsCount, string town) { Car[] cars = new Car[carsCount]; ... } }
class Transporter { public string Name { get; private set; } public Transporter(string name) { this.Name = name; } public void Deliver(Car[] cars, string town) { Console.WriteLine("Delivering {0} car(s) to {1} by {2}", cars.Length, town, this.Name); } }
static class TransporterLocator { static IList<Transporter> transporters = new List<Transporter>(); public static void Register(Transporter transporter) { transporters.Add(transporter); } public static Transporter Locate(string name) { return transporters .Where(transporter => transporter.Name == name) .Single(); } }
class CarProducer { public void DeliverTo(int carsCount, string town) { Car[] cars = new Car[carsCount]; Transporter transporter = null; if (carsCount <= 12) transporter = TransporterLocator.Locate("truck"); else transporter = TransporterLocator.Locate("train"); transporter.Deliver(cars, town); } }
TransporterLocator.Register(new Transporter("truck")); TransporterLocator.Register(new Transporter("train")); CarProducer producer = new CarProducer(); producer.DeliverTo(7, "Tehran"); producer.DeliverTo(74, "Tehran");
TransporterLocator.Register(new Transporter("truck")); CarProducer producer = new CarProducer(); producer.DeliverTo(7, "Tehran"); producer.DeliverTo(74, "Tehran");
class CarProducer { private Transporter truck; private Transporter train; public CarProducer(Transporter truck, Transporter train) { if (truck == null) throw new ArgumentNullException("truck"); if (train == null) throw new ArgumentNullException("train"); this.truck = truck; this.train = train; } public void DeliverTo(int carsCount, string town) { Car[] cars = new Car[carsCount]; Transporter transporter = this.truck; if (carsCount > 12) transporter = this.train; transporter.Deliver(cars, town); } }
//Person.cs
namespace DependencyInjectionForDummies
{
class Person
{
public string Name { get; set; }
}
}
//Car.cs
using System;
using System.Collections.Generic;
namespace DependencyInjectionForDummies
{
class Car
{
List<Person> _passengers = new List<Person>();
public void AddPassenger(Person p)
{
_passengers.Add(p);
Console.WriteLine("{0} added!", p.Name);
}
public void Drive()
{
foreach (var passenger in _passengers)
Console.WriteLine("Driving {0} ...!", passenger.Name);
}
}
}
//Driver.cs
using System.Collections.Generic;
namespace DependencyInjectionForDummies
{
class Driver
{
private Car _myCar = new Car();
public void DriveToMarket(IList<Person> passengers)
{
foreach (var passenger in passengers)
_myCar.AddPassenger(passenger);
_myCar.Drive();
}
}
}
//Program.cs
using System.Collections.Generic;
using System;
namespace DependencyInjectionForDummies
{
class Program
{
static void Main(string[] args)
{
new Driver().DriveToMarket(
new List<Person>
{
new Person{ Name="Ali" },
new Person{ Name="Vahid" }
});
Console.WriteLine("Press a key ...");
Console.ReadKey();
}
}
}
//ICar.cs
using System;
namespace DependencyInjectionForDummies
{
interface ICar
{
void AddPassenger(Person p);
void Drive();
}
}
//Car.cs
using System;
using System.Collections.Generic;
namespace DependencyInjectionForDummies
{
class Car : ICar
{
//همانند قسمت قبل
}
}
//Van.cs
using System;
using System.Collections.Generic;
namespace DependencyInjectionForDummies
{
class Van : ICar
{
List<Person> _passengers = new List<Person>();
public void AddPassenger(Person p)
{
_passengers.Add(p);
Console.WriteLine("{0} added!", p.Name);
}
public void Drive()
{
foreach (var passenger in _passengers)
Console.WriteLine("Driving {0} ...!", passenger.Name);
}
}
}
//Driver.cs
using System.Collections.Generic;
namespace DependencyInjectionForDummies
{
class Driver
{
private ICar _myCar;
public Driver(ICar myCar)
{
_myCar = myCar;
}
public void DriveToMarket(IList<Person> passengers)
{
foreach (var passenger in passengers)
_myCar.AddPassenger(passenger);
_myCar.Drive();
}
}
}
//Program.cs
using System.Collections.Generic;
using System;
namespace DependencyInjectionForDummies
{
class Program
{
static void Main(string[] args)
{
Driver driver = new Driver(new Van());
driver.DriveToMarket(
new List<Person>
{
new Person{ Name="Ali" },
new Person{ Name="Vahid" }
});
Console.WriteLine("Press a key ...");
Console.ReadKey();
}
}
}
public class AbstractFactory { public static T CreateObject<T>() where T : class , new() { return new T(); } }
public class Product { public void DisplayInfo() { Console.WriteLine("Product Class Craeted. "); } }
public class Category { public void DisplayInfo() { Console.WriteLine("Category Class Created."); } }
static void Main(string[] args) { var p = AbstractFactory.CreateObject< Product>(); p.DisplayInfo(); Console.WriteLine("======"); var c = AbstractFactory.CreateObject<Category>(); c.DisplayInfo(); Console.WriteLine("======"); Console.ReadKey(); }
public partial class SidebarMenuController : Controller { const int Min15 = 900; [ChildActionOnly] [OutputCache(Duration = Min15)] public virtual ActionResult Index() { return PartialView("_SidebarMenu"); } }
using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Core1RtmEmptyTest.Services; namespace Core1RtmEmptyTest.ViewComponents { public class SiteCopyright : ViewComponent { private readonly IMessagesService _messagesService; public SiteCopyright(IMessagesService messagesService) { _messagesService = messagesService; } public IViewComponentResult Invoke(int numberToTake) { var name = _messagesService.GetSiteName(); return View(viewName: "Default", model: name); } //public async Task<IViewComponentResult> InvokeAsync(int numberToTake) //{ // return View(); //} } }
/Views/Shared/Components/[NameOfComponent]/Default.cshtml
/Views/[CurrentController]/Components/[NameOfComponent]/Default.cshtml
<footer> <p>@await Component.InvokeAsync("SiteCopyright", new { numberToTake = 5 })</p> </footer>
[ViewComponent] public abstract class ViewComponent { protected ViewComponent(); public HttpContext HttpContext { get; } public ModelStateDictionary ModelState { get; } public HttpRequest Request { get; } public RouteData RouteData { get; } public IUrlHelper Url { get; set; } public IPrincipal User { get; } [Dynamic] public dynamic ViewBag { get; } [ViewComponentContext] public ViewComponentContext ViewComponentContext { get; set; } public ViewContext ViewContext { get; } public ViewDataDictionary ViewData { get; } public ICompositeViewEngine ViewEngine { get; set; } //... }
public IActionResult AddURLTest() { return ViewComponent("AddURL"); }
$(document).ready (function(){ $("#LoadSignIn").click(function(){ $('#UserControl').load("/Home/AddURLTest"); }); });
"dependencies": { "NETStandard.Library": "1.6.0", "Microsoft.AspNetCore.Mvc": "1.0.0", "Microsoft.AspNetCore.Razor.Tools": { "version": "1.0.0-preview2-final", "type": "build" } }, "tools": { "Microsoft.AspNetCore.Razor.Tools": "1.0.0-preview2-final" }
"buildOptions": { "embed": "Views/**/*.cshtml" }
public void ConfigureServices(IServiceCollection services) { services.AddMvc(); //Get a reference to the assembly that contains the view components var assembly = typeof(ViewComponentLibrary.ViewComponents.SimpleViewComponent).GetTypeInfo().Assembly; //Create an EmbeddedFileProvider for that assembly var embeddedFileProvider = new EmbeddedFileProvider(assembly,"ViewComponentLibrary"); //Add the file provider to the Razor view engine services.Configure<RazorViewEngineOptions>(options => { options.FileProviders.Add(embeddedFileProvider); });
[ViewComponent(Name = "ViewComponentLibrary.Simple")] public class SimpleViewComponent : ViewComponent
@await Component.InvokeAsync("ViewComponentLibrary.Simple", new { number = 5 })
using System.ComponentModel.DataAnnotations; namespace BlazorWasmUpload.Shared { public class User { [Required] public string Name { get; set; } [Required] [Range(18, 90)] public int Age { get; set; } } }
namespace BlazorWasmUpload.Server.Controllers { [ApiController] [Route("api/[controller]/[action]")] public class FilesController : ControllerBase { [HttpPost] public async Task<IActionResult> CreateUser( [FromForm] User userModel, [FromForm] IList<IFormFile> inputFiles = null)
using System.Collections.Generic; using System.Linq; using System.Net.Http; using System.Net.Http.Headers; using System.Text; using System.Text.Json; using System.Threading.Tasks; using Microsoft.AspNetCore.Components.Forms; namespace BlazorWasmUpload.Client.Services { public interface IFilesManagerService { Task<HttpResponseMessage> PostModelWithFilesAsync<T>(string requestUri, IEnumerable<IBrowserFile> browserFiles, string fileParameterName, T model, string modelParameterName); } public class FilesManagerService : IFilesManagerService { private readonly HttpClient _httpClient; public FilesManagerService(HttpClient httpClient) { _httpClient = httpClient; } public async Task<HttpResponseMessage> PostModelWithFilesAsync<T>( string requestUri, IEnumerable<IBrowserFile> browserFiles, string fileParameterName, T model, string modelParameterName) { var requestContent = new MultipartFormDataContent(); requestContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data"); if (browserFiles?.Any() == true) { foreach (var file in browserFiles) { var stream = file.OpenReadStream(maxAllowedSize: 512000 * 1000); requestContent.Add(content: new StreamContent(stream, (int)file.Size), name: fileParameterName, fileName: file.Name); } } requestContent.Add( content: new StringContent(JsonSerializer.Serialize(model), Encoding.UTF8, "application/json"), name: modelParameterName); var result = await _httpClient.PostAsync(requestUri, requestContent); result.EnsureSuccessStatusCode(); return result; } } }
namespace BlazorWasmUpload.Client { public class Program { public static async Task Main(string[] args) { var builder = WebAssemblyHostBuilder.CreateDefault(args); // ... builder.Services.AddScoped<IFilesManagerService, FilesManagerService>(); // ... } } }
@code { IReadOnlyList<IBrowserFile> SelectedFiles; User UserModel = new User(); bool isProcessing; string UploadErrorMessage;
@page "/" @using System.IO @using BlazorWasmUpload.Shared @using BlazorWasmUpload.Client.Services @inject IFilesManagerService FilesManagerService <h3>Post a model with files</h3> <EditForm Model="UserModel" OnValidSubmit="CreateUserAsync"> <DataAnnotationsValidator /> <div> <label>Name</label> <InputText @bind-Value="UserModel.Name"></InputText> <ValidationMessage For="()=>UserModel.Name"></ValidationMessage> </div> <div> <label>Age</label> <InputNumber @bind-Value="UserModel.Age"></InputNumber> <ValidationMessage For="()=>UserModel.Age"></ValidationMessage> </div> <div> <label>Photos</label> <InputFile multiple disabled="@isProcessing" OnChange="OnInputFileChange" /> @if (!string.IsNullOrWhiteSpace(UploadErrorMessage)) { <div> @UploadErrorMessage </div> } @if (SelectedFiles?.Count > 0) { <table> <thead> <tr> <th>Name</th> <th>Size (bytes)</th> <th>Last Modified</th> <th>Type</th> </tr> </thead> <tbody> @foreach (var selectedFile in SelectedFiles) { <tr> <td>@selectedFile.Name</td> <td>@selectedFile.Size</td> <td>@selectedFile.LastModified</td> <td>@selectedFile.ContentType</td> </tr> } </tbody> </table> } </div> <div> <button disabled="@isProcessing">Create user</button> </div> </EditForm>
private void OnInputFileChange(InputFileChangeEventArgs args) { var files = args.GetMultipleFiles(maximumFileCount: 15); if (args.FileCount == 0 || files.Count == 0) { UploadErrorMessage = "Please select a file."; return; } var allowedExtensions = new List<string> { ".jpg", ".png", ".jpeg" }; if(!files.Any(file => allowedExtensions.Contains(Path.GetExtension(file.Name), StringComparer.OrdinalIgnoreCase))) { UploadErrorMessage = "Please select .jpg/.jpeg/.png files only."; return; } SelectedFiles = files; UploadErrorMessage = string.Empty; }
private async Task CreateUserAsync() { try { isProcessing = true; await FilesManagerService.PostModelWithFilesAsync( requestUri: "api/Files/CreateUser", browserFiles: SelectedFiles, fileParameterName: "inputFiles", model: UserModel, modelParameterName: "userModel"); UserModel = new User(); } finally { isProcessing = false; SelectedFiles = null; } }
using System.IO; using Microsoft.AspNetCore.Mvc; using BlazorWasmUpload.Shared; using Microsoft.AspNetCore.Hosting; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using System.Collections.Generic; using Microsoft.Extensions.Logging; using System.Text.Json; using BlazorWasmUpload.Server.Utils; using System.Linq; namespace BlazorWasmUpload.Server.Controllers { [ApiController] [Route("api/[controller]/[action]")] public class FilesController : ControllerBase { private const int MaxBufferSize = 0x10000; private readonly IWebHostEnvironment _webHostEnvironment; private readonly ILogger<FilesController> _logger; public FilesController( IWebHostEnvironment webHostEnvironment, ILogger<FilesController> logger) { _webHostEnvironment = webHostEnvironment; _logger = logger; } [HttpPost] public async Task<IActionResult> CreateUser( //[FromForm] string userModel, // <-- this is the actual form of the posted model [ModelBinder(BinderType = typeof(JsonModelBinder)), FromForm] User userModel, [FromForm] IList<IFormFile> inputFiles = null) { /*var user = JsonSerializer.Deserialize<User>(userModel); _logger.LogInformation($"userModel.Name: {user.Name}"); _logger.LogInformation($"userModel.Age: {user.Age}");*/ _logger.LogInformation($"userModel.Name: {userModel.Name}"); _logger.LogInformation($"userModel.Age: {userModel.Age}"); var uploadsRootFolder = Path.Combine(_webHostEnvironment.WebRootPath, "Files"); if (!Directory.Exists(uploadsRootFolder)) { Directory.CreateDirectory(uploadsRootFolder); } if (inputFiles?.Any() == true) { foreach (var file in inputFiles) { if (file == null || file.Length == 0) { continue; } var filePath = Path.Combine(uploadsRootFolder, file.FileName); using var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None, MaxBufferSize, useAsync: true); await file.CopyToAsync(fileStream); _logger.LogInformation($"Saved file: {filePath}"); } } return Ok(); } } }
[ModelBinder(BinderType = typeof(JsonModelBinder)), FromForm] User userModel,
using System; using System.Text.Json; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc.ModelBinding; namespace BlazorWasmUpload.Server.Utils { public class JsonModelBinder : IModelBinder { public Task BindModelAsync(ModelBindingContext bindingContext) { if (bindingContext == null) { throw new ArgumentNullException(nameof(bindingContext)); } var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName); if (valueProviderResult != ValueProviderResult.None) { bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult); var valueAsString = valueProviderResult.FirstValue; var result = JsonSerializer.Deserialize(valueAsString, bindingContext.ModelType); if (result != null) { bindingContext.Result = ModelBindingResult.Success(result); return Task.CompletedTask; } } return Task.CompletedTask; } } }
[HttpPost] public async Task<IActionResult> CreateUser( [FromForm] string userModel, // <-- this is the actual form of the posted model [FromForm] IList<IFormFile> inputFiles = null) { var user = JsonSerializer.Deserialize<User>(userModel);
Controller Factory و Action Invoker وظیفهای مطابق نامشان را عهده دار هستند. اولی برای وهله سازی کنترلرهای مرتبط با درخواست و دومی برای پیدا کردن و تریگر نمودن یک اکشن متد به کار گرفته میشوند. فریم ورک MVC پیاده سازی پیش فرضی را از این دو کامپوننت، به صورت توکار دارد. در طی مقالاتی نحوهی کنترل کردن رفتار پیش فرض این Controller Factory و هم نحوهی جایگزین کرن کامل این کامپوننت را بررسی میکنیم.
namespace ControllerExtensibility.Models { public class Result { public string ControllerName { get; set; } public string ActionName { get; set; } } }
@model ControllerExtensibility.Models.Result @{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>Result</title> </head> <body> <div>Controller: @Model.ControllerName</div> <div>Action: @Model.ActionName</div> </body> </html>
using ControllerExtensibility.Models; using System.Web.Mvc; namespace ControllerExtensibility.Controllers { public class ProductController : Controller { public ViewResult Index() { return View("Result", new Result { ControllerName = "Product", ActionName = "Index" }); } public ViewResult List() { return View("Result", new Result { ControllerName = "Product", ActionName = "List" }); } } }
using System.Web.Mvc; namespace ControllerExtensibility.Controllers { public class CustomerController : Controller { public ViewResult Index() { return View("Result", new Result { ControllerName = "Customer", ActionName = "Index" }); } public ViewResult List() { return View("Result", new Result { ControllerName = "Customer", ActionName = "List" }); } } }
using System.Web.Routing; using System.Web.SessionState; namespace System.Web.Mvc { public interface IControllerFactory { IController CreateController(RequestContext requestContext, string controllerName); SessionStateBehavior GetControllerSessionBehavior(RequestContext requestContext, string controllerName); void ReleaseController(IController controller); } }
using System; using System.Web.Mvc; using System.Web.Routing; using System.Web.SessionState; using ControllerExtensibility.Controllers; namespace ControllerExtensibility.Infrastructure { public class CustomControllerFactory : IControllerFactory { public IController CreateController(RequestContext requestContext, string controllerName) { Type targetType = null; switch (controllerName) { case "Product": targetType = typeof (ProductController); break; case "Customer": targetType = typeof (CustomerController); break; default: requestContext.RouteData.Values["controller"] = "Product"; targetType = typeof (ProductController); break; } return targetType == null ? null : (IController) DependencyResolver.Current.GetService(targetType); } public SessionStateBehavior GetControllerSessionBehavior(RequestContext requestContext, string controllerName) { return SessionStateBehavior.Default; } public void ReleaseController(IController controller) { IDisposable disposable = controller as IDisposable; if (disposable != null) { disposable.Dispose(); } } } }
نام | نوع | توضیحات |
HttpContext | HttpContextBase | حاوی اطلاعاتی در خصوص درخواست است. |
RouteData | RouteData | حاوی اطلاعاتی در خصوص Rout است که با درخواست رسیده همخوانی دارد. |
default: requestContext.RouteData.Values["controller"] = "Product"; targetType = typeof(ProductController); break;
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Http; using System.Web.Mvc; using System.Web.Routing; using ControllerExtensibility.Infrastructure; namespace ControllerExtensibility { public class MvcApplication : System.Web.HttpApplication { protected void Application_Start() { AreaRegistration.RegisterAllAreas(); WebApiConfig.Register(GlobalConfiguration.Configuration); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); ControllerBuilder.Current.SetControllerFactory(new CustomControllerFactory()); } } }
و جواب داد! در همین تصویر میبینید که یه کلاس CustomTemplate هم دارم که اون هم ITableTemplate رو پیاده سازی کرده و بعد از این کلاس در سایر اسمبلیها استفاده کردم و شاید اگه این اینترفیس رو داخل اسمبلیهای خودشون پیاده سازی میکردم، با اون هم به مشکل میخوردم.
مشکلم حل شده الان ولی خودم دقیقا نفهمیدم چطور!
ممنون