• 在ASP.NET Web API中使用OData的单例模式


    从OData v4开始增加了对单例模式的支持,我们不用每次根据主键等来获取某个EDM,就像在C#中使用单例模式一样。实现方式大致需要两步:

    1、在需要实现单例模式的导航属性上加上[Singleton]特性
    2、在EDM配置的时候使用builder.Singleton<SomeModel>("SomeModels")来创建SingletonConfiguration<SomeModel>

    首先还是从模型开始。

    public class Employee
    {
        public int ID { get; set; }
        public string Name { get; set; }
    
        [Singleton]
        public Company Company { get; set; }
    }
    
    public enum CompanyCategory
    {
        IT = 0,
        Communication = 1,
        Electronics = 2,
        Others = 3
    }
    
    public class Company
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public Int64 Revenue { get; set; }
        public CompanyCategory Category { get; set; }
        public List<Employee> Employees { get; set; }
    }

    以上,Company和Employee存在1对多关系,我们在Employee的Compnay导航属性上加上了[Singleton]特性,也就意味着我们希望在Company上使用单例模式。

    然后就在WebApiConfig中配置如下:

    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            ...
    
            config.MapODataServiceRoute("ODataRoute", "odata", GetEdmModel());
        }
    
        public static IEdmModel GetEdmModel()
        {
            ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
    
            EntitySetConfiguration<Employee> employeesConfiguration = builder.EntitySet<Employee>("Employees");
            EntityTypeConfiguration<Employee> employeeTypeConfiguration = employeesConfiguration.EntityType;
            employeeTypeConfiguration.Action("ResetDataSource");
    
    
            SingletonConfiguration<Company> companiesConfiguration = builder.Singleton<Company>("Umbrella");
            companiesConfiguration.EntityType.Action("ResetDataSource");
            companiesConfiguration.EntityType.Function("GetEmployeesCount").Returns<int>();
    
            builder.Namespace = "Hello";
    
            return builder.GetEdmModel();
        }
    }

    以上,builder.Singleton<Company>("Umbrella")方法创建SingletonConfiguration<Company>类型的实例,这是EDM实现单例的方式。


    Company对应的控制器UmbrellaController

    再来看Company对应的控制器,大致如下:

    public class UmbrellaController : ODataController
    {
        public static Company Umbrella;
    
        static UmbrellaController()
        {
            InitData();
        }
    
        private static void InitData()
        {
            Umbrella = new Company()
            {
                ID = 1,
                Name = "Umbrella",
                Revenue = 1000,
                Category = CompanyCategory.Communication,
                Employees = new List<Employee>()
            };
        }
        
        ...
        
        [HttpPost]
        public IHttpActionResult ResetDataSourceOnCompany()
        {
            InitData();
            return StatusCode(HttpStatusCode.NoContent);
        }
    
        public IHttpActionResult GetEmployeesCount()
        {
            return Ok(Umbrella.Employees.Count);
        }
    }

    以上,UmbrellaController提供的静态Company类型的Umbrella可以在全局获取。ResetDataSourceOnCompany对应配置单例EDM的companiesConfiguration.EntityType.Action("ResetDataSource")的Action,GetEmployeesCount对应配置单例EDM的companiesConfiguration.EntityType.Function("GetEmployeesCount").Returns<int>()的Function。

    ● 查询

    [EnableQuery]
    public IHttpActionResult Get()
    {
        return Ok(Umbrella);
    }
    
    public IHttpActionResult GetRevenueFromCompany()
    {
        return Ok(Umbrella.Revenue);
    }
    
    public IHttpActionResult GetName()
    {
        return Ok(Umbrella.Employees);
    }

    以上,GetRevenueFromCompany和GetName分别获取属性,要符合惯例,即"Get+属性名称"。

    ● 添加

    public IHttpActionResult Put(Company newCompany)
    {
        Umbrella = newCompany;
        return StatusCode(HttpStatusCode.NoContent);
    }

    ● Patch

    public IHttpActionResult Patch(Delta<Company> item)
    {
        item.Patch(Umbrella);
        return StatusCode(HttpStatusCode.NoContent);
    }

    ● 创建Company上的Employees关系

    /// <summary>
    /// 创建Company上Employees的关系
    /// </summary>
    /// <param name="navigationProperty"></param>
    /// <param name="link">Empolyee的uri地址</param>
    /// <returns></returns>
    [AcceptVerbs("POST")]
    public IHttpActionResult CreateRef(string navigationProperty, [FromBody] Uri link)
    {
        //获取Employee的外键
        int employeeId = HelperFunction.GetKeyValue<int>(link);
        Employee employee = EmployeesController.Employees.First(x => x.ID == employeeId);
    
        if(employee == null || navigationProperty!="Employees")
        {
            return BadRequest();
        }
    
        if(Umbrella.Employees == null)
        {
            Umbrella.Employees = new List<Employee>() { employee};
        }
        else
        {
            Umbrella.Employees.Add(employee);
        }
        return StatusCode(HttpStatusCode.NoContent);
    }

    其实就是往Company的Employees集合导航属性中添加一个元素。其中,HelperFunction.GetKeyValue<int>()方法用来获取link中Empoyee的主键。如下:

    public static class HelperFunction
    {
        //获取主键值
        public static TKey GetKeyValue<TKey>(Uri uri)
        {
            if(uri ==null)
            {
                throw new ArgumentException("uri");
            }
    
            var rootPath = uri.AbsoluteUri.Substring(0, uri.AbsoluteUri.LastIndexOf('/') + 1);
            var odataUriParser = new ODataUriParser(WebApiConfig.GetEdmModel(), new Uri(rootPath), uri);
            var odataPath = odataUriParser.ParsePath();
            var keySegment = odataPath.LastSegment as KeySegment;
            if(keySegment==null)
            {
                throw new InvalidOperationException("The link does not contain a key");
            }
            return (TKey)keySegment.Keys.First().Value;
        }
    }

    ● 删除Company上的Employees关系

    /// <summary>
    /// 删除关系
    /// </summary>
    /// <param name="relatedKey">Employee的主键</param>
    /// <param name="navigationProperty"></param>
    /// <returns></returns>
    public IHttpActionResult DeleteRef(string relatedKey, string navigationProperty)
    {
        int key = int.Parse(relatedKey);
        Employee employee = Umbrella.Employees.First(x => x.ID == key);
    
        if(navigationProperty != "Employees")
        {
            return BadRequest();
        }
    
        Umbrella.Employees.Remove(employee);
        return StatusCode(HttpStatusCode.NoContent);
    }

    其实就是删除Company的集合属性Employees中的一个Employee元素。


    ● 往Company的Employees集合里添加一个Employee元素

    /// <summary>
    /// 从Compnay处添加某个Employee
    /// </summary>
    /// <param name="employee"></param>
    /// <returns></returns>
    [HttpPost]
    public IHttpActionResult PostToEmployees([FromBody] Employee employee)
    {
        EmployeesController.Employees.Add(employee);
        if(Umbrella.Employees == null)
        {
            Umbrella.Employees = new List<Employee>() { employee };
        }
        else
        {
            Umbrella.Employees.Add(employee);
        }
        return Created(employee);
    }

    EmployeesController不详诉

    public class EmployeesController : ODataController
    {
        public static List<Employee> Employees;
    
        static EmployeesController()
        {
            InitData();
        }
    
        private static void InitData()
        {
            Employees = Enumerable.Range(0, 10).Select(i =>
                   new Employee()
                   {
                       ID = i,
                       Name = string.Format("Name {0}", i)
                   }).ToList();
        }
    
        [EnableQuery]
        public IHttpActionResult Get()
        {
            return Ok(Employees.AsQueryable());
        }
    
        [EnableQuery]
        public IHttpActionResult Get(int key)
        {
            return Ok(Employees.Where(e => e.ID == key));
        }
    
        public IHttpActionResult GetCompanyFromEmployee([FromODataUri] int key)
        {
            var company = Employees.First(e => e.ID == key).Company;
            if(company==null)
            {
                return StatusCode(HttpStatusCode.NotFound);
            }
            return Ok(company);
        }
    
        public IHttpActionResult Post([FromBody] Employee employee)
        {
            Employees.Add(employee);
            return Created(employee);
        }
    
        [AcceptVerbs("PUT")]
        public IHttpActionResult CreateRef([FromODataUri] int key, string navigationProperty, [FromBody] Uri link)
        {
            if(navigationProperty!="Company")
            {
                return BadRequest();
            }
            Employees.First(e => e.ID == key).Company = UmbrellaController.Umbrella;
            return StatusCode(HttpStatusCode.NoContent);
    
        }
    
    
        public IHttpActionResult DeleteRef([FromODataUri] int key, string navigationProperty)
        {
            if(navigationProperty!="Company")
            {
                return BadRequest();
            }
    
            Employees.First(e => e.ID == key).Company = null;
            return StatusCode(HttpStatusCode.NoContent);
        }
    
        public IHttpActionResult PutToCompany(int key, Company company)
        {
            var navigateCompany = Employees.First(e => e.ID == key).Company;
            Employees.First(e => e.ID == key).Company = company;
            if(navigateCompany.Name == "Umbrella")
            {
                //体现Singleton
                UmbrellaController.Umbrella = navigateCompany;
            }
            else
            {
                return BadRequest();
            }
            return StatusCode(HttpStatusCode.NoContent);
        }
    
        public IHttpActionResult PatchToCompany(int key, Delta<Company> company)
        {
            var navigateCompan = Employees.First(e => e.ID == key).Company;
            company.Patch(Employees.First(e => e.ID == key).Company);
    
            if(navigateCompan.Name == "Umbrella")
            {
                company.Patch(UmbrellaController.Umbrella);
            }
            else
            {
                return BadRequest();
            }
            return StatusCode(HttpStatusCode.NoContent);
        }
    
        [HttpPost]
        public IHttpActionResult ResetDataSourceOnCollectionOfEmployee()
        {
            InitData();
            return Ok();
        }
    }
  • 相关阅读:
    顺序表和链表优缺点
    指针和引用
    常见操作系统面试题
    网络套接字编程(UDP)
    Windows下的问题
    解决虚拟机选择桥接模式连不上网(CentOs6.5)
    DevOps平台实践
    Prometheus实现k8s集群的服务监控
    Kubernetes集群的日志EFK解决方案
    Helm
  • 原文地址:https://www.cnblogs.com/darrenji/p/4952184.html
Copyright © 2020-2023  润新知