如何使用Autofac注入automapper 使用

extjs+MVC4+PetaPoco+AutoFac+AutoMapper后台管理系统(附源码)-爱编程
extjs+MVC4+PetaPoco+AutoFac+AutoMapper后台管理系统(附源码)
本项目使用的开发环境及技术列举如下:1、开发环境IDE:VS2010+MVC4数据库:SQLServer20082、技术前端:Extjs后端:(1)、数据持久层:轻量级ORM框架PetaPoco(2)、依赖注入:AutoFac(3)、对象关系映射:AutoMapper(4)、数据验证(MVC自带的验证封装使用)(5)、SQL翻译机(6)、缓存
以上使用都参考或直接借鉴使用了园子内牛人们的代码,只是学习交流使用而已,还请勿怪,我为了简便,没有分多个类库,而是以文件夹的形式分的,大家可以根据文件夹分成类库也是一样的。好了,废话不多说,还是先上几张图大家看看吧,如果有兴趣再往下看
要点一:Extjs
本项目虽然功能不多,但是基本已经涵盖了extjs的所有基本用法了,对于一般的extjs初学者或是简单应用的开发应该是足够了,后 台开发主要在tab、grid、treegrid的用法比较多,也是比较麻烦的地方,下面直接上代码,大家看看
首页布局:
2 * 程序主入口
4 Ext.onReady(function () {
* 上,panel.Panel
this.topPanel = Ext.create('Ext.panel.Panel', {
region: 'north',
height: 55
* 左,panel.Panel
this.leftPanel = Ext.create('Ext.panel.Panel', {
region: 'west',
title: '主菜单',
iconCls: 'House',
width: 200,
layout: 'accordion',
collapsible: true
* 右,tab.Panel
this.rightPanel = Ext.create('Ext.tab.Panel', {
region: 'center',
layout: 'fit',
id: 'mainContent',
collapisble: true,
tabWidth: 120,
items: [{ title: '首页', html: ' &iframe scrolling="auto" frameborder="0" width="100%" height="100%" src="' + DefaultUrl + '"& &/iframe&'}]
* 下,panel.Panel
this.bottomPanel = Ext.create('Ext.panel.Panel', {
region: 'south',
layout: 'fit',
id: 'foot',
collapisble: true,
height: 30,
html:'&div&欢迎您光临!&/div&'
Ext.define('TreeModelExtension', {
extend: 'Ext.data.Model',
//当Model实体类模型被用在某个TreeStore上,并且第一次实例化的时候 ,这些个属性会添加到Model实体类的的原型(prototype )上 (至于上述代码,则是通过把他设置为根节点的时候触发实例化处理的)
{name: 'text',
type: 'string'},
{name: 'url',
type: 'string'}
var buildTree = function (json) {
return Ext.create('Ext.tree.Panel', {
rootVisible: false,
border: false,
store: Ext.create('Ext.data.TreeStore', {
model:'TreeModelExtension',
expanded: true,
children: json.children
listeners: {
'itemdblclick': function (view, record, item,
index, e) {
var id = record.get('id');
var text = record.get('text');
var iconCls = record.get('iconCls');
var leaf = record.get('leaf');
var url = record.get('url');
if (leaf) {
//没有子节点时才创建新的tab显示
var tabs = Ext.getCmp('mainContent');
//获取布局页的Tab组件
var Loadtab = Ext.getCmp(id);
//判断Tab是否已经加载
if(Loadtab==undefined){
//未加载则加载
tabs.add({
closable: true,
//这种方式采取了加载多个iframe的方式,优化看如何采取一个iframe的方式
html: ' &iframe scrolling="auto" frameborder="0" width="100%" height="100%" src="' + url + '"& &/iframe&',
iconCls: iconCls,
title: text
//已加载则设置为活动页
//tabs.setActiveTab(id);
//适合于数据量较大,但是不需要实时改变得情况下,直接将已打开的tab设置为活动tab
//适合于需要实时展示最新数据的情况,先移除已打开的此tab,然后再重新加载
tabs.remove(id);
tabs.add({
closable: true,
//这种方式采取了加载多个iframe的方式,优化看如何采取一个iframe的方式
html: ' &iframe scrolling="auto" frameborder="0" width="100%" height="100%" src="' + url + '"& &/iframe&',
iconCls: iconCls,
title: text
scope: this
* 加载菜单树
Ext.Ajax.request({
url: AjaxPath,
success: function (response) {
var json = Ext.JSON.decode(response.responseText)
Ext.each(json.data, function (el) {
var panel = Ext.create(
'Ext.panel.Panel', {
id: el.id,
title: el.text,
iconCls:el.iconCls,
layout: 'fit'
panel.add(buildTree(el));
leftPanel.add(panel);
failure: function (request) {
Ext.MessageBox.show({
title: '操作提示',
msg: "连接服务器失败",
buttons: Ext.MessageBox.OK,
icon: Ext.MessageBox.ERROR
method: 'post'
* Viewport
Ext.create('Ext.container.Viewport', {
layout: 'border',
renderTo: Ext.getBody(),
items: [this.topPanel, this.leftPanel, this.rightPanel, this.bottomPanel]
Grid行内增删改查:
1 Ext.onReady(function () {
ExtJS组件自适应浏览器大小改变,看还有没有其他实现方式
Ext.EventManager.onWindowResize(function () {
ponentManager.each(function (cmpId, cmp, length) {
if (cmp.hasOwnProperty("renderTo")) {
cmp.doLayout();
var toolbar = Ext.create('Ext.toolbar.Toolbar', {
renderTo: document.body,
// 使用右对齐容器
'-&', // 等同 { xtype: 'tbfill' }
xtype: 'textfield',
name: 'roleName',
id: 'roleName',
emptyText: '输入角色名关键字',
listeners: {
specialkey: function (field, e) {
if (e.getKey() == Ext.EventObject.ENTER) {
store.load({
//传递查询条件参数
roleName: Ext.getCmp('roleName').getValue()
// xtype: 'button', // 默认的工具栏类型
text: '查询',
tooltip: '根据数据条件查询数据',
iconCls: "Zoom",
listeners: {
click: function () {
store.load({
//传递查询条件参数
roleName: Ext.getCmp('roleName').getValue()
// 添加工具栏项之间的垂直分隔条
'-', // 等同 {xtype: 'tbseparator'} 创建 Ext.toolbar.Separator
// xtype: 'button', // 默认的工具栏类型
text: '重置',
tooltip: '清空当前查询条件',
iconCls: "Arrowrotateanticlockwise",
handler: function () {
//此事件可以代替click事件
Ext.getCmp('roleName').setValue("");
60 //1.定义Model
61 Ext.define("BeiDream.model.BeiDream_Role", {
extend: "Ext.data.Model",
{ name: 'ID', type: 'int' },
{ name: 'Name', type: 'string' },
{ name: 'Description', type: 'string' },
{ name: 'IsUsed', type: 'boolean', defaultValue: true }
70 //2.创建store
71 var store = Ext.create("Ext.data.Store", {
model: "BeiDream.model.BeiDream_Role",
autoLoad: true,
pageSize: 10,
type: 'ajax',
read: RoleListUrl, //查询
create: AddUrl, //创建
update: UpdateUrl, //更新,必须真正修改了才会触发
destroy: RemoveUrl //删除
type: 'json',
root: 'data'
type: 'json',
//默认格式
//MVC下后台使用模型自动进行转换,如果是普通webform,则配置root:'data',encode:'true',这样之后就可以使用request【data】获取
writeAllFields: true,
//false只提交修改过的字段
allowSingle: false
//默认为true,为true时,一条数据不以数组形式提交,为false时,都以数组形式提交,这样避免了提交了一条数据时,后台是list模型无法接收到数据问题
listeners: {
exception: function (proxy, response, operation) {
grid.store.load();
//删除失败,数据重新加载
var resText = Ext.decode(response.responseText);
Ext.MessageBox.show({
title: '服务器端异常',
msg: resText.msg,
icon: Ext.MessageBox.ERROR,
buttons: Ext.Msg.OK
sorters: [{
//排序字段。
property: 'id'
110 store.on('beforeload', function (store, options) {
var params = { roleName: Ext.getCmp('roleName').getValue() };
Ext.apply(store.proxy.extraParams, params);
114 var Gridtoolbar = Ext.create('Ext.toolbar.Toolbar', {
renderTo: document.body,
text: '新增',
tooltip: '新增一条数据',
iconCls: 'Add',
handler: function () {
RowEditing.cancelEdit();
// Create a model instance
var r = new BeiDream.model.BeiDream_Role();
Ext.getCmp('RoleGrid').getStore().insert(0, r);
RowEditing.startEdit(0, 0);
text: '编辑',
tooltip: '编辑当前选择行数据',
iconCls: 'Pencil',
handler: function () {
RowEditing.cancelEdit();
var data = Ext.getCmp("RoleGrid").getSelectionModel().getSelection();
RowEditing.startEdit(data[0].index, 0);
disabled: true
itemId: 'removeUser',
text: '删除',
tooltip: '可以多选删除多条数据',
iconCls: 'Delete',
handler: function () {
Ext.MessageBox.confirm('提示', '确定删除该记录?', function (btn) {
if (btn != 'yes') {
var sm = Ext.getCmp('RoleGrid').getSelectionModel();
RowEditing.cancelEdit();
var store = Ext.getCmp('RoleGrid').getStore();
store.remove(sm.getSelection());
store.sync(); //根据状态执行对应的服务器方法,delete,放在remove后才能成功执行服务器方法
if (store.getCount() & 0) {
sm.select(0);
disabled: true
itemId: 'gridSync',
text: '保存',
tooltip: '保存到服务器',
iconCls: 'Disk',
handler: function () {
grid.store.sync();
mitChanges();
//执行commitChanges()提交数据修改。
itemId: 'gridCancel',
text: '取消',
tooltip: '取消所有的已编辑数据',
iconCls: 'Decline',
handler: function () {
Ext.MessageBox.confirm('提示', '确定取消已编辑数据吗?', function (btn) {
if (btn != 'yes') {
grid.store.rejectChanges();
//执行rejectChanges()撤销所有修改,将修改过的record恢复到原来的状态
itemId: 'gridrefresh',
text: '刷新',
tooltip: '重新加载数据',
iconCls: 'Arrowrefresh',
handler: function () {
grid.store.load();
}, '-&', {
itemId: 'ImportExcel',
text: '导入Excel',
tooltip: '导入角色数据',
iconCls: 'Pageexcel',
handler: function () {
Ext.MessageBox.show({
title: '暂未开放',
msg: '即将开放',
icon: Ext.MessageBox.ERROR,
buttons: Ext.Msg.OK
itemId: 'ExportExcel',
text: '导出Ecxel',
tooltip: '角色数据导出Excel',
iconCls: 'Pageexcel',
handler: function () {
Ext.MessageBox.show({
title: '暂未开放',
msg: '即将开放',
icon: Ext.MessageBox.ERROR,
buttons: Ext.Msg.OK
218 var RowEditing = Ext.create('Ext.grid.plugin.RowEditing', { // 行编辑模式
clicksToEdit: 2,
//双击进行修改
autoCancel: false,
saveBtnText: '确定',
cancelBtnText: '取消',
errorsText: '错误',
dirtyText: '你要确认或取消更改',
listeners: {
cancelEdit: function (rowEditing, context) {
// Canceling editing of a locally added, unsaved record: remove it
if (context.record.phantom) {
//服务器上是否有此条记录的标志,true为没有
store.remove(context.record);
Edit: function (rowEditing, context) {
//store.sync();
//根据状态执行对应的服务器方法,Add/Edit
var IsValidate = ValidateInput(context.record.data, context.record.phantom);
if (!IsValidate) {
grid.store.rejectChanges();
validateedit: function (rowEditing, context) {
244 function ValidateInput(data, IsAdd) {
Ext.Ajax.request({
url: ValidateInputUrl,
method: 'POST',
jsonData: data,
params: { IsAdd: IsAdd },
async: false,
success: function (response) {
var resText = Ext.decode(response.responseText);
if (resText.success) {
Ext.MessageBox.alert('警告', resText.msg);
IsValidate = false;
IsValidate = true;
failure: function (response, options) {
Ext.MessageBox.alert('服务器异常', response.status);
return IsV
267 //多选框变化
268 function selectchange() {
var count = this.getCount();
if (count == 0) {
Gridtoolbar.items.items[2].disable();
Gridtoolbar.items.items[4].disable();
Gridtoolbar.items.items[2].enable();
Gridtoolbar.items.items[4].enable();
280 //3.创建grid
281 var grid = Ext.create("Ext.grid.Panel", {
id: "RoleGrid",
xtype: "grid",
store: store,
columnLines: true,
renderTo: Ext.getBody(),
selModel: {
injectCheckbox: 0,
listeners: {
'selectionchange': selectchange
mode: "MULTI",
//"SINGLE"/"SIMPLE"/"MULTI"
checkOnly: false
//只能通过checkbox选择
selType: "checkboxmodel",
columns: [
{ xtype: "rownumberer", text: "序号", width: 40, align: 'center' },
{ id: "id", text: "ID", width: 40, dataIndex: 'ID', sortable: true, hidden: true },
{ text: '角色名称', dataIndex: 'Name', flex: 1, editor: "textfield" },
{ text: '角色描述', dataIndex: 'Description', flex: 1, editor: "textfield" },
{ text: '是否启用', dataIndex: 'IsUsed', flex: 1, xtype: 'checkcolumn', editor: { xtype: 'checkbox', cls: 'x-grid-checkheader-editor'} }
plugins: [RowEditing],
listeners: {
itemdblclick: function (me, record, item, index, e, eOpts) {
//双击事件的操作
tbar: Gridtoolbar,
bbar: { xtype: "pagingtoolbar", store: store, displayInfo: true, emptyMsg: "没有记录" }
TreeGrid展示:前台代码和后台模型结合
Ext.onReady(function () {
ExtJS组件自适应浏览器大小改变,看还有没有其他实现方式
Ext.EventManager.onWindowResize(function () {
ponentManager.each(function (cmpId, cmp, length) {
if (cmp.hasOwnProperty("renderTo")) {
cmp.doLayout();
Ext.create('Ext.container.Viewport', {
layout: 'border',
renderTo: Ext.getBody(),
title: '主菜单模块',
region: 'west',
xtype: 'panel',
margins: '5 0 0 5',
width: 200,
collapsible: true,
// 可折叠/展开
id: 'NavigationMenucontainer',
layout: 'fit'
title: '子菜单列表',
region: 'center',
// 必须指定中间区域
xtype: 'panel',
layout: 'fit',
id: 'Gridcontainer',
margins: '5 5 0 0'
var NavigationMenu=Ext.getCmp('NavigationMenucontainer');
* 加载菜单树
Ext.Ajax.request({
url: AjaxPath,
success: function (response) {
var json = Ext.JSON.decode(response.responseText)
Ext.each(json.data, function (el) {
var panel = Ext.create(
'Ext.panel.Panel', {
id: el.id,
layout: 'fit'
var ShowGrid=CreateGrid(el.id);
Gridcontainer.add(ShowGrid);
//初始化,加载主菜单下的菜单
panel.add(buildTree(el));
NavigationMenu.add(panel);
failure: function (request) {
Ext.MessageBox.show({
title: '操作提示',
msg: "连接服务器失败",
buttons: Ext.MessageBox.OK,
icon: Ext.MessageBox.ERROR
method: 'post'
var Gridcontainer=Ext.getCmp('Gridcontainer');
Ext.define('TreeModelExtension', {
extend: 'Ext.data.Model',
//当Model实体类模型被用在某个TreeStore上,并且第一次实例化的时候 ,这些个属性会添加到Model实体类的的原型(prototype )上 (至于上述代码,则是通过把他设置为根节点的时候触发实例化处理的)
{name: 'text',
type: 'string'},
{name: 'url',
type: 'string'}
var buildTree = function (json) {
return Ext.create('Ext.tree.Panel', {
id:'MenuTree',
rootVisible: true,
border: false,
store: Ext.create('Ext.data.TreeStore', {
model:'TreeModelExtension',
id:json.id,
text:json.text,
iconCls: json.iconCls,
expanded: json.expanded,
children: json.children
listeners: {
'itemclick': function (view, record, item,
index, e) {
var ParentID = record.get('id');
var ShowGrid=CreateGrid(ParentID);
Gridcontainer.add(ShowGrid);
scope: this
function CreateGrid(ParentID) {
var Gridtoolbar = Ext.create('Ext.toolbar.Toolbar', {
renderTo: document.body,
text: '新增',
tooltip: '新增一条数据',
iconCls: 'Add',
handler: function () {
RowEditing.cancelEdit();
// Create a model instance
var r = new BeiDream.model.BeiDream_NavigationMenu();
Ext.getCmp('NavigationMenuGrid').getStore().insert(0, r);
RowEditing.startEdit(0, 0);
text: '编辑',
tooltip: '编辑当前选择行数据',
iconCls: 'Pencil',
handler: function () {
RowEditing.cancelEdit();
var data = Ext.getCmp("NavigationMenuGrid").getSelectionModel().getSelection();
RowEditing.startEdit(data[0].index, 0);
disabled: true
itemId: 'removeUser',
text: '删除',
tooltip: '可以多选删除多条数据',
iconCls: 'Delete',
handler: function () {
Ext.MessageBox.confirm('提示', '确定删除该记录?', function (btn) {
if (btn != 'yes') {
var sm = Ext.getCmp('NavigationMenuGrid').getSelectionModel();
RowEditing.cancelEdit();
var store = Ext.getCmp('NavigationMenuGrid').getStore();
store.remove(sm.getSelection());
store.sync(); //根据状态执行对应的服务器方法,delete,放在remove后才能成功执行服务器方法
if (store.getCount() & 0) {
sm.select(0);
disabled: true
itemId: 'gridSync',
text: '保存',
tooltip: '保存到服务器',
iconCls: 'Disk',
handler: function () {
var grid=Ext.getCmp('NavigationMenuGrid');
grid.store.sync();
mitChanges();
//执行commitChanges()提交数据修改。
itemId: 'gridCancel',
text: '取消',
tooltip: '取消所有的已编辑数据',
iconCls: 'Decline',
handler: function () {
Ext.MessageBox.confirm('提示', '确定取消已编辑数据吗?', function (btn) {
if (btn != 'yes') {
var grid=Ext.getCmp('NavigationMenuGrid');
grid.store.rejectChanges();
//执行rejectChanges()撤销所有修改,将修改过的record恢复到原来的状态
itemId: 'gridrefresh',
text: '刷新',
tooltip: '重新加载数据',
iconCls: 'Arrowrefresh',
handler: function () {
var grid=Ext.getCmp('NavigationMenuGrid');
grid.store.load();
var RowEditing = Ext.create('Ext.grid.plugin.RowEditing', { // 行编辑模式
clicksToEdit: 2,
//双击进行修改
autoCancel: false,
saveBtnText: '确定',
cancelBtnText: '取消',
errorsText: '错误',
dirtyText: '你要确认或取消更改',
listeners: {
beforeedit: function (rowEditing,e,context) {
if(e.colldx==2 && e.record.data.IsLeaf==false){
cancelEdit: function (rowEditing, context) {
// Canceling editing of a locally added, unsaved record: remove it
if (context.record.phantom) {
//服务器上是否有此条记录的标志,true为没有
store.remove(context.record);
Edit: function (rowEditing, context) {
//store.sync();
//根据状态执行对应的服务器方法,Add/Edit
//var IsValidate = ValidateInput(context.record.data, context.record.phantom);
if (!IsValidate) {
grid.store.rejectChanges();
function ValidateInput(data, IsAdd) {
Ext.Ajax.request({
url: ValidateInputUrl,
method: 'POST',
jsonData: data,
params: { IsAdd: IsAdd },
async: false,
success: function (response) {
var resText = Ext.decode(response.responseText);
if (resText.success) {
Ext.MessageBox.alert('警告', resText.msg);
IsValidate = false;
IsValidate = true;
failure: function (response, options) {
Ext.MessageBox.alert('服务器异常', response.status);
return IsV
//多选框变化
function selectchange() {
var count = this.getCount();
if (count == 0) {
Gridtoolbar.items.items[2].disable();
Gridtoolbar.items.items[4].disable();
Gridtoolbar.items.items[2].enable();
Gridtoolbar.items.items[4].enable();
//1.定义Model
Ext.define("BeiDream.model.BeiDream_NavigationMenu", {
extend: "Ext.data.Model",
{ name: 'ID', type: 'int' },
{ name: 'ParentID', type: 'int' },
{ name: 'ShowName', type: 'string', defaultValue: '名称......' },
{ name: 'IsLeaf', type: 'boolean', defaultValue: true },
{ name: 'url', type: 'string' },
{ name: 'OrderNo', type: 'int', defaultValue: 1 },
{ name: 'iconCls', type: 'string' },
{ name: 'Expanded', type: 'boolean', defaultValue: false }
//2.创建store
var store = Ext.create("Ext.data.Store", {
model: "BeiDream.model.BeiDream_NavigationMenu",
autoLoad: true,
pageSize: 15,
type: 'ajax',
read: MenuListUrl, //查询
create: AddUrl, //创建
update: UpdateUrl, //更新,必须真正修改了才会触发
destroy: RemoveUrl //删除
type: 'json',
root: 'data'
type: 'json',
//默认格式
//MVC下后台使用模型自动进行转换,如果是普通webform,则配置root:'data',encode:'true',这样之后就可以使用request【data】获取
writeAllFields: true,
//false只提交修改过的字段
allowSingle: false
//默认为true,为true时,一条数据不以数组形式提交,为false时,都以数组形式提交,这样避免了提交了一条数据时,后台是list模型无法接收到数据问题
listeners: {
exception: function (proxy, response, operation) {
var grid=Ext.getCmp('NavigationMenuGrid');
grid.store.load();
//删除失败,数据重新加载
var resText = Ext.decode(response.responseText);
Ext.MessageBox.show({
title: '服务器端异常',
msg: resText.msg,
icon: Ext.MessageBox.ERROR,
buttons: Ext.Msg.OK
store.on('beforeload', function (store, options) {
var params = { ParentID: ParentID };
Ext.apply(store.proxy.extraParams, params);
return Ext.create("Ext.grid.Panel", {
id: "NavigationMenuGrid",
xtype: "grid",
store: store,
columnLines: true,
selModel: {
injectCheckbox: 0,
listeners: {
'selectionchange': selectchange
mode: "SINGLE",
//"SINGLE"/"SIMPLE"/"MULTI"
checkOnly: false
//只能通过checkbox选择
selType: "checkboxmodel",
columns: [
{ xtype: "rownumberer", text: "序号", width: 40, align: 'center' },
{ id: "id", text: "ID", width: 40, dataIndex: 'ID', sortable: true, hidden: true },
{ id: "id", text: "ParentID", width: 40, dataIndex: 'ParentID', sortable: true, hidden: true },
{ text: '名称', dataIndex: 'ShowName', flex: 1, editor: {
xtype: 'textfield',
allowBlank: false
{ text: '是否为模块', dataIndex: 'IsLeaf', flex: 1, xtype: 'checkcolumn', editor: { xtype: 'checkbox', cls: 'x-grid-checkheader-editor'} },
{ text: '控制器路径', dataIndex: 'url', flex: 1, editor : {
xtype: 'combobox',
editable:false,
listeners: {
//点击下拉列表事件
expand: function (me, event, eOpts) {
var grid=Ext.getCmp('NavigationMenuGrid');
var record = grid.getSelectionModel().getLastSelected();
if(record!=null){
if(record.data.IsLeaf==true){
currentComboBox =
f_openSelectControllerWin();
Ext.MessageBox.alert('警告', '只有模块才拥有控制器!');
{ text: '排序号', dataIndex: 'OrderNo',align:"center", width: 48, flex: 1,editor: {
xtype: 'numberfield',
allowBlank: false,
minValue: 1,
maxValue: 150000
{ text: '图标', dataIndex: 'iconCls',align:"center", width: 48,renderer : function(value) {
return "&div Align='center' style='height:16width:16px' class="+value+"&&/div&";
} ,editor : {
xtype: 'combobox',
editable:false,
listeners: {
//点击下拉列表事件
expand: function (me, event, eOpts) {
currentComboBox =
f_openIconsWin();
{ text: '是否展开', dataIndex: 'Expanded', flex: 1, xtype: 'checkcolumn', editor: { xtype: 'checkbox', cls: 'x-grid-checkheader-editor'} }
plugins: [RowEditing],
tbar: Gridtoolbar,
bbar: { xtype: "pagingtoolbar", store: store, displayInfo: true, emptyMsg: "没有记录" }
要点二:后台MVC的传参绑定,返回值自定义
MVC方便了Ajax的异步实现,并且方便的模型传参,代码如下
/// &summary&
/// 返回数据库新增后的实体,供前台的extjs的 grid的store更新数据,这样就不需要进行重新加载store了,删,改类似
/// &/summary&
/// &param name="Roles"&&/param&
/// &returns&&/returns&
[Anonymous]
[HttpPost]
public ActionResult Add(List&BeiDream_Role& Roles)
List&BeiDream_Role& AddRoles = new List&BeiDream_Role&();
List&Object& ListObj = RoleService.Add(Roles);
if (ListObj.Count == 0)
List&string& msg = new List&string&();
msg.Add("添加角色失败!");
return this.ExtjsJsonResult(false, msg);
foreach (var item in ListObj)
AddRoles.Add(RoleService.GetModelByID(item));
List&string& msg = new List&string&();
msg.Add("添加角色成功!");
return this.ExtjsJsonResult(true, AddRoles, msg);
可以看到我直接通过后台模型来接收前台传递过来的参数,而不需要去一一解析参数值
返回值自定义:重写了ActionResult,实现了extjs需要的返回值
/// &summary&
/// 扩展的jsonResult模型,适用于extjs需要的json数据类型
/// &/summary&
public class JsonResultExtension:ActionResult
public bool success { get; set; }
public string msg { get; set; }
public object data { get; set; }
public long? total { get; set; }
public Dictionary&string, string& errors { get; set; }
/// &summary&
/// 是否序列化为extjs需要的json格式,否则进行普通序列化
/// &/summary&
public bool ExtjsUISerialize { get; set; }
public override void ExecuteResult(ControllerContext context)
if (context == null)
throw new ArgumentNullException("context");
HttpResponseBase response = context.HttpContext.R
response.ContentType = "application/json";
StringWriter sw = new StringWriter();
//IsoDateTimeConverter timeFormat = new IsoDateTimeConverter();
//timeFormat.DateTimeFormat = "yyyy-MM-dd HH:mm:ss";
IsoDateTimeConverter timeFormat = new IsoDateTimeConverter();
timeFormat.DateTimeFormat = "yyyy-MM-dd";
JsonSerializer serializer = JsonSerializer.Create(
new JsonSerializerSettings
Converters = new JsonConverter[] { timeFormat },
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
NullValueHandling = NullValueHandling.Ignore
//忽略为null的值序列化
using (JsonWriter jsonWriter = new JsonTextWriter(sw))
jsonWriter.Formatting = Formatting.I
if (ExtjsUISerialize)
serializer.Serialize(jsonWriter, this);
serializer.Serialize(jsonWriter, data);
response.Write(sw.ToString());
特性标注及权限验证,代码如下
/// &summary&
/// 权限拦截
/// &/summary&
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)]
public class PermissionFilterAttribute : ActionFilterAttribute
/// &summary&
/// 权限拦截
/// &/summary&
/// &param name="filterContext"&&/param&
public override void OnActionExecuting(ActionExecutingContext filterContext)
if (!this.CheckAnonymous(filterContext))
//未登录验证
if (SessionHelper.Get("UserID") == null)
//跳转到登录页面
filterContext.RequestContext.HttpContext.Response.Redirect("~/Admin/User/Login");
/// &summary&
/// [Anonymous标记]验证是否匿名访问
/// &/summary&
/// &param name="filterContext"&&/param&
/// &returns&&/returns&
public bool CheckAnonymous(ActionExecutingContext filterContext)
//验证是否是匿名访问的Action
object[] attrsAnonymous = filterContext.ActionDescriptor.GetCustomAttributes(typeof(AnonymousAttribute), true);
//是否是Anonymous
var Anonymous = attrsAnonymous.Length == 1;
通过写一个BaseController来进行权限的验证,这样就不需要所有需要验证的Controller加标注了,当然BaseController还可以增加其他通用的处理
/// &summary&
/// Admin后台系统公共控制器(需要验证的模块)
/// &/summary&
[PermissionFilter]
public class BaseController:Controller
&要点三:轻量级ORM框架PetaPoco &
  非侵入性ORM框架,只需要一个PetaPoco.cs文件就OK了,不过我对其进行了再次封装,实现了工作单元,还是上代码吧
& & & 一:封装
public interface IDataRepository&TEntity& : IDependency where TEntity : class
#region 属性
/// &summary&
获取 当前实体的查询数据集
/// &/summary&
Database PetaPocoDB { get; }
#endregion
#region 公共方法
/// &summary&
插入实体记录
/// &/summary&
/// &param name="entity"& 实体对象 &/param&
/// &returns& 操作影响的行数 &/returns&
bool Add(TEntity entity);
/// &summary&
批量插入实体记录集合
/// &/summary&
/// &param name="entities"& 实体记录集合 &/param&
/// &returns& 操作影响的行数 &/returns&
List&object& Add(IEnumerable&TEntity& entities);
/// &summary&
删除实体记录
/// &/summary&
/// &param name="entity"& 实体对象 &/param&
/// &returns& 操作影响的行数 &/returns&
int Delete(TEntity entity);
/// &summary&
删除实体记录集合
/// &/summary&
/// &param name="entities"& 实体记录集合 &/param&
/// &returns& 操作影响的行数 &/returns&
bool Delete(IEnumerable&TEntity& entities);
/// &summary&
更新实体记录
/// &/summary&
/// &param name="entity"& 实体对象 &/param&
/// &returns& 操作影响的行数 &/returns&
int Update(TEntity entity);
/// &summary&
更新实体记录
/// &/summary&
/// &param name="entity"& 实体对象 &/param&
/// &returns& 操作影响的行数 &/returns&
bool Update(IEnumerable&TEntity& entities);
/// &summary&
/// 根据主键ID获取实体
/// &/summary&
/// &param name="KeyID"&主键ID&/param&
/// &returns&实体&/returns&
TEntity GetModelByID(object KeyID);
/// &summary&
/// 动态查询,返回dynamic类型的列表
/// 请使用标准SQL语句进行查询(SELECT ... FROM ...)
/// &/summary&
/// &returns&&/returns&
PagedList&dynamic& DynamicPagedList(int pageIndex, int pageSize, Sql sql);
PagedList&TEntity& PagedList(int pageIndex, int pageSize, string sql, params object[] args);
PagedList&TEntity& PagedList(int pageIndex, int pageSize, Sql sql);
PagedList&TDto& PagedList&TDto&(int pageIndex, int pageSize, string sql, params object[] args);
PagedList&TDto& PagedList&TDto&(int pageIndex, int pageSize, Sql sql);
#endregion
& & &二:使用,具体封装和使用,大家还是去下载源码看吧
public class NavigationMenuService : DbContextBase&BeiDream_NavigationMenu&, INavigationMenuService, IDependency
public NavigationMenuService(IUnitOfWork unitOfWork)
: base(unitOfWork)
public List&NavigationMenu& GetNavigationMenu(int id)
var sql = Sql.Builder.Where("ParentID=@0",id);
sql.OrderBy("OrderNo ASC");
//默认ASC升序,降序为DESC
List&BeiDream_NavigationMenu& List = this.PetaPocoDB.Fetch&BeiDream_NavigationMenu&(sql);
return AutoMapperHelper.GetMapper(List);
public List&NavigationMenu& GetNavigationMenuNoLeaf(int id)
var sql = Sql.Builder.Where("ParentID=@0", id);
sql.Where("IsLeaf=@0", false);
sql.OrderBy("OrderNo ASC");
//默认ASC升序,降序为DESC
List&BeiDream_NavigationMenu& List = this.PetaPocoDB.Fetch&BeiDream_NavigationMenu&(sql);
return AutoMapperHelper.GetMapper(List);
/// &summary&
/// 递归查询产品分类列表
/// &/summary&
/// &param name="list"&父级产品分类列表&/param&
public void GetNavigationMenus(ref List&NavigationMenu& list)
foreach (NavigationMenu season in list)
List&NavigationMenu& lstSeason = GetNavigationMenu(season.id);
season.children = lstS
if (list.Count & 0)
GetNavigationMenus(ref lstSeason);
/// &summary&
/// 递归查询产品分类列表
/// &/summary&
/// &param name="list"&父级产品分类列表&/param&
public void GetNavigationMenusNoLeaf(ref List&NavigationMenu& list)
foreach (NavigationMenu season in list)
List&NavigationMenu& lstSeason = GetNavigationMenuNoLeaf(season.id);
season.children = lstS
if (list.Count & 0)
GetNavigationMenusNoLeaf(ref lstSeason);
要点四:依赖注入框架Autofac
目前使用心得最大的好处就是不需要配置即实现了面向接口编程,特别是和MVC结合,实现构造函数注入就更加方便了,当然它还有其他 功能,比如生命周期唯一实例,单例啊等等,暂时还研究不深,只是简单应用,大家看看具体实现吧
private static void AutofacMvcRegister()
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterGeneric(typeof(DbContextBase&&)).As(typeof(IDataRepository&&));
Type baseType = typeof(IDependency);
Assembly[] assemblies = Assembly.GetExecutingAssembly().GetReferencedAssemblies()
.Select(Assembly.Load).ToArray();
assemblies = assemblies.Union(new[] { Assembly.GetExecutingAssembly() }).ToArray();
builder.RegisterAssemblyTypes(assemblies)
.Where(type =& baseType.IsAssignableFrom(type) && !type.IsAbstract)
.AsImplementedInterfaces().InstancePerLifetimeScope();//InstancePerLifetimeScope 保证生命周期基于请求
//builder.RegisterType&DefaultCacheAdapter&().PropertiesAutowired().As&ICacheStorage&();
builder.RegisterControllers(Assembly.GetExecutingAssembly());
builder.RegisterFilterProvider();
IContainer container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
要点五;对象关系映射AutoMapper
目前也只是简单应用,先看代码,它是如何简化我们的工作量的
public static List&NavigationMenu& GetMapper(List&BeiDream_NavigationMenu& List)
List&NavigationMenu& NavigationMenuList = new List&NavigationMenu&();
foreach (var item in List)
//NavigationMenu DaoModel = new NavigationMenu();
//DaoModel.id = item.ID;
//DaoModel.text = item.ShowN
//DaoModel.leaf = item.IsL
//DaoModel.url = item.
//DaoModel.Expanded = item.E
//DaoModel.children =
NavigationMenu DaoModel = item.ToDestination&BeiDream_NavigationMenu, NavigationMenu&();
NavigationMenuList.Add(DaoModel);
return NavigationMenuL
注释掉的是不使用automapper之前的代码,没注释掉的是使用automapper,扩展了方法直接一句代码实现转化,是不是很easy,当然实 现这些之前,我们需要给他定义规则,然后还要注册,代码如下,具体的请看源码
public class NavigationMenuProfile : Profile
protected override void Configure()
CreateMap&BeiDream_NavigationMenu, NavigationMenu&()
.ForMember(dest =& dest.id, opt =& opt.MapFrom(src =& src.ID))
.ForMember(dest =& dest.text, opt =& opt.MapFrom(src =& src.ShowName))
.ForMember(dest =& dest.leaf, opt =& opt.MapFrom(src =& src.IsLeaf));
要点六:数据验证
extjs前台验证我们已经做了,但是客户端传来的东西我们不能完全相信,后台需要再次验证,我们看到mvc的官方demo。一句话就实现 了验证,我们是不是可以自己做验证呢,看代码
[Anonymous]
public ActionResult SaveUser(BeiDream_User model, List&int& Roles)
var ValidateResult = Validation.Validate(model);//服务器端的验证
if (ValidateResult.IsValid)
//验证成功
bool IsExitUser = UserService.PetaPocoDB.Exists&BeiDream_User&(model.ID);
if (!IsExitUser)
FilterGroup userRoleGroup = new FilterGroup();
FilterHelper.CreateFilterGroup(userRoleGroup, null, "UserName", model.UserName, GroupOperatorQueryEnum.and, RuleOperatorQueryEnum.equal);
bool IsExist = UserService.IsExist(userRoleGroup);
if (IsExist)
List&string& errorName=new List&string&();
errorName.Add("UserName");
ValidationResult error = new ValidationResult("已存在相同的用户名", errorName);
ValidateResult.Add(error);
return this.ExtjsFromJsonResult(false,ValidateResult);
bool IsSaveSuccess = TransactionService.AddUserAndUserRole(model, Roles);
List&string& msg = new List&string&();
msg.Add(IsSaveSuccess ? "用户信息保存成功!" : "用户信息保存失败!");
return this.ExtjsFromJsonResult(true, null, msg);
FilterGroup userRoleGroup = new FilterGroup();
FilterHelper.CreateFilterGroup(userRoleGroup, null, "UserName", model.UserName, GroupOperatorQueryEnum.and, RuleOperatorQueryEnum.equal);
FilterHelper.CreateFilterGroup(userRoleGroup, null, "ID", model.ID, GroupOperatorQueryEnum.and, RuleOperatorQueryEnum.notequal);
bool IsExist = UserService.IsExist(userRoleGroup);
if (IsExist)
List&string& errorName = new List&string&();
errorName.Add("UserName");
ValidationResult error = new ValidationResult("已存在相同的用户名", errorName);
ValidateResult.Add(error);
return this.ExtjsFromJsonResult(false, ValidateResult);
bool IsSaveSuccess = TransactionService.UpdateUserAndUserRole(model, Roles);
List&string& msg = new List&string&();
msg.Add(IsSaveSuccess ? "用户信息保存成功!" : "用户信息保存失败!");
return this.ExtjsFromJsonResult(true, null, msg);
return this.ExtjsFromJsonResult(false,ValidateResult);
//验证失败,返回失败的验证结果,给出前台提示信息
大家可以看到前台传进来的参数,我们先进行验证&var ValidateResult = Validation.Validate(model),验证的条件我们是在模型上定义好的,然后判断验证是否通过,通过进行下一步动作,不通过,把验证的结果信息返回前台,提示给用户
要点七:SQL翻译机
这个只能算是一个简单的东西吧,并且感觉用起来麻烦,但是我觉得用的熟练了,还是很不错的,只是省了手拼SQL的问题嘛,减少了出 错几率,具体使用还是看代码吧
[Anonymous]
public ActionResult GetUserList(int page, int start, int limit, string UserKeyName, string RoleID)
RemoveSelectId();
PagedList&BeiDream_User& PageList = null;
FilterGroup userGroup = GetQueryConditions(UserKeyName, RoleID);
PageList = UserService.GetPagedList(page, limit, userGroup);
return this.ExtjsGridJsonResult(PageList, PageList.TotalItemCount);
private FilterGroup GetQueryConditions(string UserKeyName, string RoleID)
FilterGroup userGroup = new FilterGroup();
if (!string.IsNullOrEmpty(RoleID))
//用户角色不为空时
FilterGroup userRoleGroup = new FilterGroup();
FilterHelper.CreateFilterGroup(userRoleGroup, null, "RoleID", RoleID, GroupOperatorQueryEnum.and, RuleOperatorQueryEnum.equal);
//先根据用户角色查出对应的用户ID
List&BeiDream_User_Role& List = UserRoleService.GetList(userRoleGroup);
if (List.Count != 0)
//todo,此角色信息为空情况下,查到的用户也应该为空,目前未处理
if (string.IsNullOrEmpty(UserKeyName))
//再根据此用户角色下的用户ID,因为查出所以用户ID,查询条件是或的关系GroupOperatorQueryEnum.or,翻译出对应用户的查询条件,最后查出对应用户
foreach (var item in List)
FilterHelper.CreateFilterGroup(userGroup, null, "ID", item.UserID, GroupOperatorQueryEnum.or, RuleOperatorQueryEnum.equal);
//先翻译出用户名查询条件,与其他查询条件是与的关系GroupOperatorQueryEnum.and
FilterHelper.CreateFilterGroup(userGroup, null, "UserName", UserKeyName, GroupOperatorQueryEnum.and, RuleOperatorQueryEnum.like);
//因为第二个查询条件是多个查询条件的结合组成再与第一个查询条件结合,故放到子FilterGroup中
List&FilterGroup& filterGroups = new List&FilterGroup&();
FilterGroup userIDGroup = new FilterGroup();
//再根据此用户角色下的用户ID,因为查出所以用户ID,查询条件是或的关系GroupOperatorQueryEnum.or,翻译出对应用户的查询条件,最后查出对应用户
foreach (var item in List)
FilterHelper.CreateFilterGroup(userIDGroup, null, "ID", item.UserID, GroupOperatorQueryEnum.or, RuleOperatorQueryEnum.equal);
filterGroups.Add(userIDGroup);
userGroup.groups = filterG
if (!string.IsNullOrEmpty(UserKeyName))
//先翻译出用户名查询条件,与其他查询条件是与的关系GroupOperatorQueryEnum.and
FilterHelper.CreateFilterGroup(userGroup, null, "UserName", UserKeyName, GroupOperatorQueryEnum.and, RuleOperatorQueryEnum.like);
return userG
要点八:缓存
&缓存也就简单应用Helper级别,主要用了.net自带缓存和分布式Memcached缓存,一个接口,两个实现
/// &summary&
/// 缓存接口
/// &/summary&
public interface ICacheStorage
#region 缓存操作
/// &summary&
/// 添加缓存
/// &/summary&
/// &param name="key"&&/param&
/// &param name="value"&&/param&
void Insert(string key, object value);
/// &summary&
/// 添加缓存(默认滑动时间为20分钟)
/// &/summary&
/// &param name="key"&key&/param&
/// &param name="value"&value&/param&
/// &param name="expiration"&绝对过期时间&/param&
void Insert(string key, object value, DateTime expiration);
/// &summary&
/// 添加缓存
/// &/summary&
/// &param name="key"&key&/param&
/// &param name="value"&value&/param&
/// &param name="expiration"&过期时间&/param&
void Insert(string key, object value, TimeSpan expiration);
/// &summary&
/// 获得key对应的value
/// &/summary&
/// &param name="key"&&/param&
/// &returns&&/returns&
object Get(string key);
/// &summary&
/// 根据key删除缓存
/// &/summary&
/// &param name="key"&&/param&
void Remove(string key);
/// &summary&
/// 缓存是否存在key的value
/// &/summary&
/// &param name="key"&key&/param&
/// &returns&&/returns&
bool Exist(string key);
/// &summary&
/// 获取所有的缓存key
/// &/summary&
/// &returns&&/returns&
List&string& GetCacheKeys();
/// &summary&
/// 清空缓存
/// &/summary&
void Flush();
#endregion
  写博客真的是很累人的事,很敬佩那些能写连载博客的牛人们,虽然自己做的项目很小,但是觉得写成博客,要写的要点还是很多的 ,上面我讲的很粗略,但是主要的知识点都讲出来了,这个项目其实没有做完,不打算再继续了,打算换了,接下来打算使用easyui
+knockout+ef来写一个完整的权限管理系统,涉及菜单权限、按钮权限、字段权限等等吧,路很长.....任重而道远
最后,大家如果觉得有帮助,请点推荐哦!源码下载地址:
版权所有 爱编程 (C) Copyright 2012. . All Rights Reserved.
闽ICP备号-3
微信扫一扫关注爱编程,每天为您推送一篇经典技术文章。

我要回帖

更多关于 autofac automapper 的文章

 

随机推荐