当前位置: 首页 > 软件库 > Web应用开发 > Web框架 >

URF.NET

Unit of Work & Repositories Framework - .NET 4.x
授权协议 MIT License
开发语言 JavaScript
所属分类 Web应用开发、 Web框架
软件类型 开源软件
地区 不详
投 递 者 慕佑运
操作系统 跨平台
开源组织
适用人群 未知
 软件概览

URF.NET    NuGet Badge

Unit-of-Work & Repository Framework | Official URF, Trackable Entities & Design Factory Team

Docs: goo.gl/6zh9zp | Subscribe URF Updates: @lelong37 | NuGet: goo.gl/WEn7Jm

This framework (over 100K+ total downloads) minimizes the surface area of your ORM technology from disseminating in your application. This framework was deliberately designed to be lightweight, small in footprint size, and non-intimidating to extend and maintain. When we say lightweight we really mean lightweight, when using this framework with the Entity Framework provider there are only 10 classes. This lightweight framework will allow you to elegantly, unobtrusively, and easily patternize your applications and systems with Repository, Unit of Work, and Domain Driven Design. To use Generic Repositories or not? The framework allows the freedom of both, generic repositories and the ability to add in your own domain specific repository methods, in short Unit of Work with extensible and generic Repositories.

Live demo: longle.azurewebsites.net

Architecture Overview (Sample Northwind Application with URF Framework)

Architecture Overview (Sample Northwind Application & Framework)

URF sample and usage in ASP.NET Web API

public class CustomerController : ODataController
{
    private readonly ICustomerService _customerService;
    private readonly IUnitOfWorkAsync _unitOfWorkAsync;

    public CustomerController(
        IUnitOfWorkAsync unitOfWorkAsync,
        ICustomerService customerService)
    {
        _unitOfWorkAsync = unitOfWorkAsync;
        _customerService = customerService;
    }

    // GET: odata/Customers
    [HttpGet]
    [Queryable]
    public IQueryable<Customer> GetCustomer()
    {
        return _customerService.Queryable();
    }

    // GET: odata/Customers(5)
    [Queryable]
    public SingleResult<Customer> GetCustomer([FromODataUri] string key)
    {
        return SingleResult.Create(_customerService.Queryable().Where(t => t.CustomerID == key));
    }

    // PUT: odata/Customers(5)
    public async Task<IHttpActionResult> Put(string key, Customer customer)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        if (key != customer.CustomerID)
        {
            return BadRequest();
        }

        customer.TrackingState = TrackingState.Modified;
        _customerService.Update(customer);

        try
        {
            await _unitOfWorkAsync.SaveChangesAsync();
        }
        catch (DbUpdateConcurrencyException)
        {
            if (!CustomerExists(key))
            {
                return NotFound();
            }
            throw;
        }

        return Updated(customer);
    }

    // POST: odata/Customers
    public async Task<IHttpActionResult> Post(Customer customer)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        customer.TrackingState = TrackingState.Added;
        _customerService.Insert(customer);

        try
        {
            await _unitOfWorkAsync.SaveChangesAsync();
        }
        catch (DbUpdateException)
        {
            if (CustomerExists(customer.CustomerID))
            {
                return Conflict();
            }
            throw;
        }

        return Created(customer);
    }

    //// PATCH: odata/Customers(5)
    [AcceptVerbs("PATCH", "MERGE")]
    public async Task<IHttpActionResult> Patch([FromODataUri] string key, Delta<Customer> patch)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        Customer customer = await _customerService.FindAsync(key);

        if (customer == null)
        {
            return NotFound();
        }

        patch.Patch(customer);
        customer.TrackingState = TrackingState.Modified;

        try
        {
            await _unitOfWorkAsync.SaveChangesAsync();
        }
        catch (DbUpdateConcurrencyException)
        {
            if (!CustomerExists(key))
            {
                return NotFound();
            }
            throw;
        }

        return Updated(customer);
    }

    // DELETE: odata/Customers(5)
    public async Task<IHttpActionResult> Delete(string key)
    {
        Customer customer = await _customerService.FindAsync(key);

        if (customer == null)
        {
            return NotFound();
        }

        customer.TrackingState = TrackingState.Deleted;

        _customerService.Delete(customer);
        await _unitOfWorkAsync.SaveChangesAsync();

        return StatusCode(HttpStatusCode.NoContent);
    }

    // GET: odata/Customers(5)/CustomerDemographics
    [Queryable]
    public IQueryable<CustomerDemographic> GetCustomerDemographics([FromODataUri] string key)
    {
        return
            _customerService.Queryable()
                .Where(m => m.CustomerID == key)
                .SelectMany(m => m.CustomerDemographics);
    }

    // GET: odata/Customers(5)/Orders
    [Queryable]
    public IQueryable<Order> GetOrders([FromODataUri] string key)
    {
        return _customerService.Queryable().Where(m => m.CustomerID == key).SelectMany(m => m.Orders);
    }

    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            _unitOfWorkAsync.Dispose();
        }
        base.Dispose(disposing);
    }

    private bool CustomerExists(string key)
    {
        return _customerService.Query(e => e.CustomerID == key).Select().Any();
    }
}

Implementing Domain Logic with URF Service Pattern

All methods that are exposed from Repository<TEntity> in Service<TEntity> are overridable to add any pre or post domain/business logic. Domain business logic should be in the Service layer and not in Controllers or Repositories for separation of concerns.

  1. Create an Interface e.g. ICustomerService, which should always inherit IService<TEnttiy> e.g. IService<Customer>
  2. Implement the concrete implementation for your Interface e.g. CustomerService which implements ICustomerService
  3. If using DI & IoC, don't forget to wire up the binding of your Interface and Implementation e.g. container.RegisterType<ICustomerService, CustomerService>(), see next example for more details on wiring up DI & IoC.
public interface ICustomerService : IService<Customer>
{
    decimal CustomerOrderTotalByYear(string customerId, int year);
    IEnumerable<Customer> CustomersByCompany(string companyName);
    IEnumerable<CustomerOrder> GetCustomerOrder(string country);
}


public class CustomerService : Service<Customer>, ICustomerService
{
    private readonly IRepositoryAsync<Customer> _repository;

    public CustomerService(IRepositoryAsync<Customer> repository) : base(repository)
    {
        _repository = repository;
    }

    public decimal CustomerOrderTotalByYear(string customerId, int year)
    {
        // add any domain logic here
        return _repository.GetCustomerOrderTotalByYear(customerId, year);
    }

    public IEnumerable<Customer> CustomersByCompany(string companyName)
    {
        // add any domain logic here
        return _repository.CustomersByCompany(companyName);
    }

    public IEnumerable<CustomerOrder> GetCustomerOrder(string country)
    {
        // add any domain logic here
        return _repository.GetCustomerOrder(country);
    }

    public override void Insert(Customer entity)
    {
        // e.g. add any business logic here before inserting
        base.Insert(entity);
    }

    public override void Delete(object id)
    {
        // e.g. add business logic here before deleting
        base.Delete(id);
    }
}

URF Sample DI & IoC Configuration with Framework of your choice, exampled here using Microsoft Unity DI & IoC

UnityConfig.cs

public class UnityConfig
{
    private static Lazy<IUnityContainer> container = new Lazy<IUnityContainer>(() =>
    {
        var container = new UnityContainer();
        RegisterTypes(container);
        return container;
    });

    public static IUnityContainer GetConfiguredContainer()
    {
        return container.Value;
    }

    public static void RegisterTypes(IUnityContainer container)
    {
        container
            // Register DbContext instead of IDataDataContext, which is now obsolete.
            //.RegisterType<IDataContextAsync, NorthwindContext>(new PerRequestLifetimeManager())
            .RegisterType<DbContext, NorthwindContext>(new PerRequestLifetimeManager())
            .RegisterType<IUnitOfWorkAsync, UnitOfWork>(new PerRequestLifetimeManager())
            .RegisterType<IRepositoryAsync<Customer>, Repository<Customer>>()
            .RegisterType<IRepositoryAsync<Product>, Repository<Product>>()
            .RegisterType<IProductService, ProductService>()
            .RegisterType<ICustomerService, CustomerService>()
            .RegisterType<INorthwindStoredProcedures, NorthwindContext>(new PerRequestLifetimeManager())
            .RegisterType<IStoredProcedureService, StoredProcedureService>();
    }
}

Roadmap: URF .NET Core (alpha-release) ETA: February 2018

  • Intial URF .NET Core release will ship with default provider Entity Framework Core, as mentioned, overtime we'll bring on more providers.
  • First and foremost, learning from current .NET URF through comments, suggestions, real world feedback from enterprise level teams, URF team's actual experiences working with other teams/projects as a guidance practice to improve while implementing new URF .NET Core version. This list is quite the list, far to much to list here, however we'll include and generate a list specific to each of our releases moving forward in URF .NET Core versions.
  • Easily implement customizations e.g. adding audit trails with adding a simple abstraction such as IAuditable to our Entity.cs base class for your Entities.
  • Quickly get up and running with URF under a minute, we've recently just started publishing URF to NuGet, we're already approaching 1000 downloads. Shipping URF as NuGet packages is definitely something we did not realize as an added value. We were mistaken that most teams would like to clone/fork and include URF projects directly in their solution for infinite customizations possibilities however this was actually not the case. In reality, most teams use URF as is, right out the box, with zero customizations.
  • Although we'll be shipping URF as NuGet packages, new .NET Core version we'll have a lazer focus on modularity. Meaning we will several URF pacakges to further open opportunities such as creating other providers for URF other than Entity Framework Core e.g. NHibernate, MongoDB, DocumentDb, Cosmos, etc...
  • Tooling, tooling, tooling. The new URF .NET Core version architeture and design will set the stage for tooling such as code generation with templating with .NET Handlbars and/or Razor. We are considering to have full parity across different runtimes .NET Core is able to run in e.g. Mac, Linux, Windows, etc. We will performing rigurous due-dilligence to ensure this (XPLAT).
  • URF .NET Core will be a completey seperate rewrite and entirely new product, will have deep throught in it's new arcitecture and design for microservices world e.g. Azure Functions, AWS Lambdas, etc...
  • URF Sample will be updated to Angular v5 and Kendo UI for Angular (Kendo UI for Angular is also a complete new product line, which is now built from the ground up with Angular vs. Kendo UI for AngularJS which was jQuery widgets wrapped with AngularJS directives)
  • URF Sample app will also demonstrate lastest versionf of OData running in ASP.NET Core Web API
  • Trackable Entities Team has already been included in current version of .NET URF, and will also be supported in .NET Core version. This is a very powerful feature, which allows Entites to self track their state (e.g. Added, Modified, Delete, None) without DbContext. This is extremely helful for tracking object graphs and maintaning all entity states in a complex object graph accross physical boundaries, again while doing so with zero dependency on DbContext and more importantly doing so with zero dependency on Entity Framework or any other data provider. We've already released Trackable Entities for TypeScript/Javascript as an NPM package, allowing teams to take advantage of self Tracking Entities not only across physical boundaries but across different runtimes as well. Most common usecase for this is SPA (Angular, ReactJS, Aurelia, Vue.js, etc...) while using Trackable Entities for TypeScript /Javascript and passing object graphs with their states to Web APIs using URF.
  • Many more improvements e.g. performance, fusioning on a few design patterns in URF's core e.g. striking the best compromise and balance between Visitor Pattern and Recursion when traversing any object graphs, and so much more and to many to list here, again, we'll include a list with every release in each versions release notes.

URF Features & Benefits

  • Repository Pattern - 100% extensible ready
  • Unit of Work Pattern - 100% atomic & transaction ready
  • Service Pattern - pattern for implementing business, domain specific logic with 100% separation of concerns e.g. ICustomerService, IOrderService
  • Minimize footprint of your ORM and data access layer
  • DI & IoC 100% ready
  • REST, Web API & OData 100% ready
  • 100% testable & mockable
  • 100% support for Stored Procedures
  • Repository Pattern supports IEnumerable and/or IQueryable
  • Trackable Entities - When using URF, entities are 100% automatically self tracking, states are automatically trackable (New, Updated, Deleted, Unchanged), allowing entity or complex object graph states to be trackable across physical boundaries and application layers. Entity state can be tracked in Angular all the way to Web API.
  • Full (Northwind) sample application (Angular, Web API, OData, Entity Framework, SQL)
  • 100% unit tests & integration tests - Integration tests, will drop and re-create NorthwindTest database everytime integration tests are ran
  • 注:c#初学者,懂得不是很多,因为最近有一个项目才开始研究的,学术不精,勿喷。 这里我们用的是明华URF-R330读写器 卡片类型M1 开发环境vs2008 由于我只需要进行对卡片的读取和修改,所以这篇文章只针对读卡写卡而生 首先我们得简单的了解一下读卡器从连接电脑到读取卡片到写卡这一个简单的过程 : 1.读卡器连接电脑,明华这款读卡器是利用USB接口的,首先是驱动吗?这个大家都懂(这里我是没有用

  • 在对接api时候,经常需要对字符串进行各种编码处理,系统可能是异构的,实现语言也就可能是不一样的。所以经常会使人犯一些2B的错误! 比如:php实现的api中用了rawurlencode,文档中写,需要对字符串进行urlencode编码,.net的开发人员看到文档,直接使用HttpUtitlity.UrlEncode,    本以为问题已经解决,实际埋下了一个大坑!     其实php的rawur

  • 项目目标部署环境:CentOS 7+ 项目技术点:.netcore2.0 + Autofac +webAPI + NHibernate5.1 + mysql5.6 + nginx  开源地址:https://github.com/wmowm/nh.core 很多小伙伴,初识.net core都不知道如何下手,从哪里开始学习,这让我想起群里经常有小伙伴问,mvc怎么学习? 我觉得,第一步应该找到一个

 相关资料
  • 我创建了一个,其中包含一个自定义。在整个应用程序中使用时,不能直接访问控件,因为它在逻辑上嵌入在中。 因此,为了访问的项,我在返回ToolStrip项的类中定义了一个属性。 现在,可以通过使用属性以编程方式编辑的项,但在设计模式下不能这样做。 就像有人将从拖动到窗体,转到,选择项的属性并相应地操作嵌入的的项;正如我们在items的帮助下使用任何标准控件的items集合一样。 在此,尽管的属性显示在

  • 问题内容: 假设有一个包含以下表的数据库: 带customer_ID(键字段),customer_name的customer_table 带order_ID(键字段),customer_ID,product_ID的orders_table 现在,假设我想查找订购了10种以上不同类型产品的所有客户的名称,以及订购的产品类型的数量。同一产品的多个订单不计算在内。 我认为下面的查询应该可以,但是有以下问

  • 问题内容: 我有一个Oracle 11g XE数据库,并且有一个查询结果集: 我想在逗号分隔的同一行中获得所有相关类别的不同ID,像这样 我以前使用过Postgres,并在那里提供了帮助。如何在Oracle 11g XE中获得相同的结果? 问题答案: 除非您在存储过程中使用它来将输出另存为数组(或集合),否则使用的查询应该足够并提供相同的输出。 在oracle中,我们没有像这样的简单转换函数。但是

  • 问题内容: 我有正在用JSP开发的应用程序,我希望以XLS(MS Excel格式)从数据库中导出一些数据。 在tomcat下,是否可以像正常的Java应用程序一样编写文件,然后生成指向该文件的链接?还是我需要使用特定的API? 这样做会不会有权限问题? 问题答案: 尽管您可以使用像JExcelAPI这样的功能强大的库,但是只要您将响应的MIME类型设置为“ application / vnd.ms

  • 问题内容: 检索适用于所有浏览器的XmlHttpRequest对象的最简单,最安全的方法是什么?没有任何额外的库。您是否经常使用一个代码段? PS:我知道网上有很多例子,但这恰恰是我要问的原因:例子太多了,我只想简单实用的东西来工作。 问题答案: 虽然我建议使用完整的库来简化用法,但是在现代浏览器中,进行AJAX请求可能非常简单: 以下代码段是基于quirksmode.org的代码段的更高级代码段

  • 问题内容: 我在SQL Server的更大的Select语句中有以下查询: 在某些条目(例如)之后,此列将生成一些奇怪的符号。我不知道这是哪里来的。我尝试`SELECT SelectedComments FROM 问题答案: 如果您修改了For Xml Path的用法,它将为您完成转义操作,并且您无需诉诸使用Replace函数:

  • 问题内容: 在我的项目中,每次打开JSP时都要分配一个变量。我在JSP和EL 中用scriptlet尝试过,它可以返回变量。 但似乎不起作用。 之后出现错误,是否无法在scriptlet中直接从EL分配变量? 问题答案: 您正在混合 脚本 和EL,并期望它们“同步”运行。那只是行不通的。一个是写的JSP的旧校园的方式 和另一种是写的JSP的现代生活方式。您应该同时使用一个或多个。 回到具体的问题,

  • 问题内容: 简而言之; 我在XML文件中生成了许多空行,并且我正在寻找一种删除它们的方法,以作为倾斜文件的一种方法。我怎样才能做到这一点 ? 详细说明;我目前有这个XML文件: 我使用此Java代码删除所有标签,并添加新标签: 在多次执行此方法后,我得到了一个XML文件,其结果正确,但是在“ paths”标记之后和第一个“ path”标记之前有许多空行,如下所示: 有人知道该如何解决吗? ----