AutoCAD 命令统计魔幻球的实现过程--(1)

简介:


前面的文章介绍了AutoCAD 命令统计魔幻球,大家有空可以玩玩看。今天开始介绍一下这个项目的实现过程。这个项目还是很简单的,其中用到的技术主要包括AutoCAD .net API, ASP.net MVC, Windows Azure, Entity Framework代码优先编程,RESTSharp, Jquery 和WebGL(Three.Js)。我首先介绍一下服务端的实现方法。

image

这个项目包括3个部分, – 一个AutoCAD插件来收集AutoCAD命令的使用情况上传到云端的服务程序, 一个驻留在Windows Azure云端的REST服务程序来接收/发送和存储命令统计信息, 另外是一个web页面中由JQuery以REST的方式从云端服务程序获取统计数据,并用WebGL渲染出来,这里使用了一个比较流行的类库Three.JS. 下面是Visual Studio的解决方案,包括5个项目。其中AcadCommandViewer是服务程序和网页浏览端,这是一个ASP.NET MVC应用,最后要部署到Windows Azure。另外还有个AutoCAD.net的插件程序。另外为了使数据模型能够重用,我把它独立出来成为一个单独的项目。

image

下面看一下服务端程序的实现。说到创建Windows Azure云端应用,你估计首先想到的就是用Windows Azure SDK的模版来创建,但是我发现这样是调试过程中在Azure 模拟器中测试还是挺慢的。其实把一个现有的asp.net 程序移植到到Windows Azure也还是很简单的,既然如此,那何不就从一个简单的ASP.NET程序开始呢? 于是我就在Visual Studio中创建了一个ASP.net MVC 4 Web Application 。

 

首先需要定义数据模型,如果项目不大,在MVC项目的Models目录下定义就好了,但上面我也提到了,这个数据模型我还是要在AutoCAD插件项目中重用的,所以把数据模型独立出来成为一个单独的项目。很简单就是添加一个class library项目,加入一个数据模型的类即可:

using System;
using System.Collections.Generic;
using System.Linq;
using
System.Web;

namespace
AcadCommandViewer.Models
{
   
public class UserCommandsHit
    {
       
public int Id { get; set
; }
       
public string UserName { get; set
; }
       
public virtual ICollection<CommandHit> CommandHits { get; set
; }

    }

   
public class CommandHit
    {
       
public int Id { get; set
; }
       
public string CommandName { get; set
; }
       
public int HitNumber { get; set; }
    }
}

 

数据模型建好了,然后可以创建控制器了。Visual Studio提供了很好的模版,我使用Web API + Entity framework,这个模版其实已经帮我做了大部分的工作。在Controllers目录上点右键,添加--控制器,选择“API controller with read/write actions, using Entity Framework“模版,并选择上面创建的数据模型类,

 

image

然后选择“<New data context>”让Visual Studio来帮我们自动创建数据上下文类。如果你在上面的模型类列表中找不到你的数据模型类,那是因为你没添加引用,因为我的数据模型已经独立到另外一个项目中了,很简单,添加引用即可:

image

 

Visual Studio自动生成的控制器代码已经相当不错了,通过Web API实现了REST服务的GET, POST ,PUT 和DELETE方法,不过在PUT方法更新时有一点问题,就是我们上面的数据模型定义中是有父子关系的,默认的代码Entity Framework不能处理这个父子关系的模型,需要稍微改一点。解决办法就是把旧记录的子对象都删除,然后在加入新对象的子对象,具体可以看一下下面的代码及注释。

 

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web;
using System.Web.Http;
using
AcadCommandViewer.Models;

namespace
AcadCommandViewer.Controllers
{
   
public class AcadCommandsController : ApiController
    {
       
private AcadCommandViewerContext db = new AcadCommandViewerContext
();

       
// GET api/AcadCommands
        public IEnumerable<UserCommandsHit
> GetCommandsDatas()
        {
           
return
db.UserCommandsHits.OrderBy(p => p.UserName)
                .AsEnumerable();
        }

       
// GET api/AcadCommands/5
        public UserCommandsHit GetCommandsData(int
id)
        {
           
UserCommandsHit
commandsdata = db.UserCommandsHits.Find(id);
           
if (commandsdata == null
)
            {
               
throw new HttpResponseException
(
                    Request.CreateResponse(
HttpStatusCode
.NotFound));
            }

           
return
commandsdata;
        }

       
// GET api/AcadCommands?username=Daniel
        public UserCommandsHit GetCommandsData(string
userName)
        {
           
UserCommandsHit
commandsdata = db.UserCommandsHits
                .FirstOrDefault<
UserCommandsHit
>(p =>
                    p.UserName.ToUpper() == userName.ToUpper());
           
if (commandsdata == null
)
            {
               
throw new HttpResponseException
(
                    Request.CreateResponse(
HttpStatusCode
.NotFound));
            }

           
return
commandsdata;
        }

       
// PUT api/AcadCommands/5
        public HttpResponseMessage PutCommandsData(int
id,
                           
UserCommandsHit
commandsdata)
        {
           
if
(ModelState.IsValid && id == commandsdata.Id)
            {
               
var
usrCmdHitInDb = db.UserCommandsHits.Find(id);
               
//http://stackoverflow.com/questions/7968598/entity-4-1-updating-an-existing-parent-entity-with-new-child-entities
                //SetValues never updates navigation properties.
                //EF doesn't have any magic to update the children
                // - which means: adding new children, deleting
                // removed children, updating existing children
                // this procedure forces you to delete the old
                // children also from the database and insert the new one
                db.Entry(usrCmdHitInDb).CurrentValues.SetValues(commandsdata);
               
//workaroud is to remove
                foreach (var ch in
usrCmdHitInDb.CommandHits.ToList())
                {
                    usrCmdHitInDb.CommandHits.Remove(ch);
                }

                usrCmdHitInDb.CommandHits.Clear();

               
foreach (var item in
commandsdata.CommandHits)
                {
                    usrCmdHitInDb.CommandHits.Add(item);
                }

               
try
                {
                    db.SaveChanges();
                }
               
catch (DbUpdateConcurrencyException
)
                {
                   
return Request.CreateResponse(HttpStatusCode
.NotFound);
                }

               
return Request.CreateResponse(HttpStatusCode
.OK);
            }
           
else
            {
               
return Request.CreateResponse(HttpStatusCode
.BadRequest);
            }
        }

       
// POST api/AcadCommands
        public HttpResponseMessage PostCommandsData(UserCommandsHit
commandsdata)
        {
           
if
(ModelState.IsValid)
            {
                db.UserCommandsHits.Add(commandsdata);
                db.SaveChanges();

               
HttpResponseMessage
response = Request
                    .CreateResponse(
HttpStatusCode
.Created, commandsdata);
                response.Headers.Location =
new Uri
(
                    Url.Link(
"DefaultApi"
,
                           
new
{ id = commandsdata.Id })
                    );
               
return
response;
            }
           
else
            {
               
return Request.CreateResponse(HttpStatusCode
.BadRequest);
            }
        }

       
// DELETE api/AcadCommands/5
        public HttpResponseMessage DeleteCommandsData(int
id)
        {
           
UserCommandsHit
commandsdata = db.UserCommandsHits.Find(id);
           
if (commandsdata == null
)
            {
               
return Request.CreateResponse(HttpStatusCode
.NotFound);
            }

            db.UserCommandsHits.Remove(commandsdata);

           
try
            {
                db.SaveChanges();
            }
           
catch (DbUpdateConcurrencyException
)
            {
               
return Request.CreateResponse(HttpStatusCode
.NotFound);
            }

           
return Request.CreateResponse(HttpStatusCode
.OK, commandsdata);
        }

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

 

上面Visual Studio已经自动帮我们创建了数据上下文类,默认是使用SQL Express,你可以看的Web.config里面的连接字符串,稍后我们可以升级到SQL Azure云端数据库。

、Please note that the context class is using SQL Express, it is easy to migrate to SQL Azure latter:

  <connectionStrings>
   
<add name="AcadCommandViewerContext" connectionString="Data Source=.\SQLEXPRESS;
Initial Catalog=AcadCommandViewerContext; Integrated Security=True;
MultipleActiveResultSets=True"

      providerName="System.Data.SqlClient" />

   

  </
connectionStrings
>

 

然后为了测试,需要弄点测试数据,在Models目录下添加一个SampleData.cs类来代码生成一点测试数据,如果要做单元测试的话也比较方便。

 

using System;
using System.Collections.Generic;
using System.Linq;
using
System.Web;

namespace
AcadCommandViewer.Models
{
   
public static class SampleData
    {
       
public static UserCommandsHit danielCmdHits = new UserCommandsHit
        {
            Id = 1,
            UserName =
"Daniel"
,
            CommandHits =
new CommandHit
[] {
                   
new CommandHit
{
                        CommandName =
"PLINE"
,
                        HitNumber  = 1
                    },
                   
new CommandHit
{
                        CommandName =
"ZOOM"
,
                        HitNumber  = 2
                    },
                   
new CommandHit
{
                        CommandName =
"LINE"
,
                        HitNumber  = 3
                    },
                   
new CommandHit
{
                        CommandName =
"Save"
,
                        HitNumber  = 4
                    }
                }
        };

       
public static UserCommandsHit jerryCmdHits = new UserCommandsHit
             {
                 Id = 2,
                 UserName =
"Jerry"
,
                 CommandHits =
new CommandHit
[]
                {
                   
new CommandHit
{
                        CommandName =
"CIRCLE"
,
                        HitNumber  = 2
                    },
                   
new CommandHit
{
                        CommandName =
"Quit"
,
                        HitNumber  = 1
                    }
                }
             };




       
public static UserCommandsHit[] userCmdsHits = new UserCommandsHit[]
        {
            danielCmdHits,
            jerryCmdHits
        };



    }
}

 

然后需要把这些测试数据生成到数据库中,Visual Studio中的Package Manager Console 很方便。从Tools—> Library Package Manager,打开Package Manager Console ,输入命令:

PM> Enable-Migrations 

Visual Studio项目中会添加一个Migrations的目录和一个Configuration.cs的类,可以在这个类的Seed方法中来生成初始数据,代码如下:

 

namespace AcadCommandViewer.Migrations
{
   
using
System;
   
using
System.Data.Entity;
   
using
System.Data.Entity.Migrations;
   
using
System.Linq;
   
using
AcadCommandViewer.Models;

   
internal sealed class Configuration : DbMigrationsConfiguration<AcadCommandViewer.Models.AcadCommandViewerContext
>
    {
       
public
Configuration()
        {
            AutomaticMigrationsEnabled =
true
;
        }

       
protected override void Seed(AcadCommandViewer.Models.AcadCommandViewerContext
context)
        {
           
//  This method will be called after migrating to the latest version.

           
//  You can use the DbSet<T>.AddOrUpdate() helper extension method
            //  to avoid creating duplicate seed data. E.g.
            //
            //    context.People.AddOrUpdate(
            //      p => p.FullName,
            //      new Person { FullName = "Andrew Peters" },
            //      new Person { FullName = "Brice Lambson" },
            //      new Person { FullName = "Rowan Miller" }
            //    );
            //

           
//SampleData s = new SampleData();
            context.UserCommandsHits.AddOrUpdate(
                p => p.UserName,
               
SampleData.userCmdsHits
                );
        }
    }
}

 

然后在package Manager Console 中运行Update-Database命令在数据库中生成数据:

PM> Update-Database

 

好了,到目前为止,服务端程序就创建完毕了,这个程序已经能够以REST的方式提供服务了,包括数据的获取,上传,更新和删除,对于REST服务的测试,可以使用Fiddler工具,这个工具的使用,你可以自行搜索,也可以看我们的另外一篇英文博客。 this post.

下来回继续接受浏览器端WebGL部分的实现。敬请关注。

作者: 峻祁连
邮箱:junqilian@163.com 
出处: http://junqilian.cnblogs.com 
转载请保留此信息。



本文转自峻祁连. Moving to Cloud/Mobile博客园博客,原文链接:http://www.cnblogs.com/junqilian/archive/2013/03/12/2955316.html ,如需转载请自行联系原作者
目录
打赏
0
0
0
0
23
分享
相关文章
图像去雨-雨线清除-图像处理-(计算机作业附代码)
图像去雨-雨线清除-图像处理-(计算机作业附代码)
用Python print画一条龙,有眼睛,会动,彩色的,还会喷火那种
古有 div画条, console画龙。 今有我 Python print 画 战龙, 一条目光凶猛,霸气红色,爱运动,能战斗的霸王龙。 上面的都是产品说的,我是研发, 所以,大家懂的,从产品到设计, 从设计到实现, 每一步都是有差距的。
1905 0
用Python print画一条龙,有眼睛,会动,彩色的,还会喷火那种
HMI-33-【运动模式】补上油量表和水温表
上一篇,以为是做了一个收尾,写了灯光控制面板和底部的信息栏,但是,有位眼见的小伙伴`江山壹角`,直接不给我面子,说我的水温表和油量表不会动。截图位置,我记仇哈。
巧用千寻位置GNSS软件| 直线放样有技巧
日常测量作业中,直线放样是对设计好的直线进行放样,其中包括直线的里程,左右偏距及设计直线范围内的高程控制。本文将介绍如何运用千寻位置GNSS软件完成日常的直线放样。
C语言——函数的综合运用。自定义函数,gotoxy清屏函数与HideCursor隐藏光标,防闪屏,共同制作打飞机游戏。
①在变量中,我们必须进行定义赋值初始化后,才能在程序中使用,所以需要一个“地方”,整理好这些变量,在程序中整洁一些void startup() //数据初始化②打出画面中所显示的所需代码,也给一个函数void show() //显示画面③在游戏运行中,飞机的移动,发射等操作必须使用键盘,此时就要进行输入判断,给出相应的函数,实行不同的命令 ,其中分为两种,一种是程序运行时对输入做出变化,另一种是不变化void updateWithoutInput() //与用户输入无关的更新。
jmeter如何进行一个简单的测试(超级详细,有图有文字,闭着眼都能成功)
jmeter如何进行一个简单的测试(超级详细,有图有文字,闭着眼都能成功)
154 0
jmeter如何进行一个简单的测试(超级详细,有图有文字,闭着眼都能成功)
Java锤子剪刀布大家应该都会玩“锤子剪刀布”的游戏: 现给出两人的交锋记录,请统计双方的胜、平、负次数,并且给出双方分别出什么手势的胜算最大。
Java锤子剪刀布大家应该都会玩“锤子剪刀布”的游戏: 现给出两人的交锋记录,请统计双方的胜、平、负次数,并且给出双方分别出什么手势的胜算最大。
176 0
Halcon标定系列(3):我个人总结的“眼在手外“和“眼在手上”的心得笔记
Halcon标定系列(3):我个人总结的“眼在手外“和“眼在手上”的心得笔记
3115 0
Halcon标定系列(3):我个人总结的“眼在手外“和“眼在手上”的心得笔记
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等