SQL Server 创建链接服务器(SSMS可以访问的有效) - 听风吹雨 - 博客园

mikel阅读(1062)

来源: SQL Server 创建链接服务器 – 听风吹雨 – 博客园

适用场景:对远程的DB进行操作。

2000与2005对比:SQL Server 2000版本中也有链接远程DB的SQL,但是功能比较弱,扩展性差,支持的查询比较简单。而SQL Server 2005版本的SSMS中已经有了 服务器对象->链接服务器 的功能点,用户首先创建一个远程DB的链接对象,之后就可以像本地表一样执行表的DML了。

创建步骤:在SQL Server 2005版本打开SSMS,服务器对象->链接服务器->右击 新建链接服务器,在图2中是一种设置方式,也有其它的设置方式,比如:[图解]sqlserver中创建链接服务器,图3是安全性选项中设置远程数据库的账号和密码。

(图1:新建链接)

(图2:设置链接)

(图3:设置帐号)

注意事项: 在MSSQL2005中Rpc的默认设置如图4所示, 需要把它设置为图5, 右键点击远程链接->属性->服务器选项->Rpc和Rpc Out,这两个值需要设置为True。

(图4: 默认设置)

(图5: 正确设置)

但在MSSQL2008下不能直接修改链接服务器 ‘ETV2_LINK’ 的RPC配置成TURE,可以通过语句修改如下:

USE [master]
GO
EXEC master.dbo.sp_serveroption @server=N’ETV2_LINK’, @optname=N’rpc’, @optvalue=N’true’
GO
EXEC master.dbo.sp_serveroption @server=N’ETV2_LINK’, @optname=N’rpc out’, @optvalue=N’true’
GO

生成脚本:如果已经通过操作界面生成了 ‘ETV2_LINK’ 的链接服务器,那么我们如果需要把它移植到其它数据库(部署、更新)的时候,就可以通过下面的方法来生产SQL脚本,你也可以通过修改SQL脚本来快速新建或修改链接服务器,比如修改@server链接服务器名称,修改@datasrc远程链接的数据库对象。

(图6: 生成SQL脚本)

SQL Server 2005生成远程链接对象的SQL脚本:

/****** 对象:  LinkedServer [ETV2_LINK]    脚本日期: 09/08/2010 17:36:11 ******/
EXEC master.dbo.sp_addlinkedserver @server = N’ETV2_LINK’, @srvproduct=N’ETV2_LINK’, @provider=N’SQLNCLI’, @datasrc=N’BWA035\BWA035_2K5′
GO
EXEC master.dbo.sp_serveroption @server=N’ETV2_LINK’, @optname=N’collation compatible’, @optvalue=N’false’
GO
EXEC master.dbo.sp_serveroption @server=N’ETV2_LINK’, @optname=N’data access’, @optvalue=N’true’
GO
EXEC master.dbo.sp_serveroption @server=N’ETV2_LINK’, @optname=N’dist’, @optvalue=N’false’
GO
EXEC master.dbo.sp_serveroption @server=N’ETV2_LINK’, @optname=N’pub’, @optvalue=N’false’
GO
EXEC master.dbo.sp_serveroption @server=N’ETV2_LINK’, @optname=N’rpc’, @optvalue=N’true’
GO
EXEC master.dbo.sp_serveroption @server=N’ETV2_LINK’, @optname=N’rpc out’, @optvalue=N’true’
GO
EXEC master.dbo.sp_serveroption @server=N’ETV2_LINK’, @optname=N’sub’, @optvalue=N’false’
GO
EXEC master.dbo.sp_serveroption @server=N’ETV2_LINK’, @optname=N’connect timeout’, @optvalue=N’0′
GO
EXEC master.dbo.sp_serveroption @server=N’ETV2_LINK’, @optname=N’collation name’, @optvalue=null
GO
EXEC master.dbo.sp_serveroption @server=N’ETV2_LINK’, @optname=N’lazy schema validation’, @optvalue=N’false’
GO
EXEC master.dbo.sp_serveroption @server=N’ETV2_LINK’, @optname=N’query timeout’, @optvalue=N’0′
GO
EXEC master.dbo.sp_serveroption @server=N’ETV2_LINK’, @optname=N’use remote collation’, @optvalue=N’true’

使用假设已经创建了名为ETV2_LINK的远程链接对象,那么你就可以像下面的方式来使用这个对象操作远程DB。

使用场景1: 查询ETV2_LINK这个远程链接对象的[etV2_Online]数据库中VisiteLog_20100629表的数据。模板形如:Select * From [链接服务器名].[远程数据库名].[所有者].[表名]

–查询远程DB表TableName
select * from ETV2_LINK.[etV2_Online].dbo.VisiteLog_20100629

使用场景2: 判断ETV2_LINK这个远程链接对象的[etV2_Online]数据库中是否存在名为VisiteLog_20100629的表。

–注意:是sys.objects不是sysobjects
–判断远程用户是否存在某张表
IF EXISTS (SELECT * FROM ETV2_LINK.[etV2_Online].sys.objects WHERE name = N’VisiteLog_20100629′ AND type in (N’U’))
BEGIN
–逻辑处理
print ‘存在表’
END

使用场景3: 判断远程DB的[etV2_Online]数据库中是否存在名为VisiteLog_20100629的表。只不过这个表名是参数化的,可以通过传入的参数进行判断。这里只是简单的设置变量的值并使用OUT来返回变量。

–判断远程用户是否存在某张表(参数化表名),返回变量
DECLARE @IsExistTable VARCHAR(10)
DECLARE @Tablename VARCHAR(50)
DECLARE @sqlString NVARCHAR(4000)
SET @IsExistTable = ‘False’
SET @Tablename = ‘VisiteLog_’+convert(varchar(9),getdate()-1,112) –例如VisiteLog_20100629
SET @sqlString =
‘IF EXISTS (SELECT * FROM ETV2_LINK.[etV2_Online].sys.objects WHERE name = N”’+@Tablename+”’ AND type in (N”U”))
set @IsExistTableOUT =”True”’
EXEC sp_executesql @sqlString,N’@IsExistTableOUT varchar(10) OUTPUT’,@IsExistTableOUT=@IsExistTable OUTPUT

IF (@IsExistTable = ‘True’)–存在
BEGIN
–逻辑处理
print ‘存在表’
END

补充: SQL Server 2000版本连接远程服务器的SQL脚本,更多相关脚步可以参考:在T-SQL语句中访问远程数据库(openrowset/opendatasource/openquery)

–方法1:
select *  from openrowset(‘SQLOLEDB’,’server=192.168.0.67;uid=sa;pwd=password’,’SELECT * FROM BCM2.dbo.tbAppl’)

–方法2:
select *  from openrowset(‘SQLOLEDB’,’192.168.0.67′;’sa’;’password’,’SELECT * FROM BCM2.dbo.tbAppl’)

链接服务器"(null)"的 OLE DB 访问接口 "SQLNCLI10" 返回了消息 "Cannot start more transactions on this session." - 潇湘隐者 - 博客园

mikel阅读(960)

来源: 链接服务器”(null)”的 OLE DB 访问接口 “SQLNCLI10” 返回了消息 “Cannot start more transactions on this session.” – 潇湘隐者 – 博客园

开发同事反馈一个SQL Server存储过程执行的时候,报“链接服务器”(null)”的 OLE DB 访问接口 “SQLNCLI10” 返回了消息 “Cannot start more transactions on this session.”。这个存储过程,个人做了一个精简和脱敏处理后如下:

BEGIN TRY    BEGIN TRANSACTION                            INSERT INTO OPENDATASOURCE(‘SQLOLEDB’, ‘DATA SOURCE=XXX.XXX.XX.XXX;USER ID=XXX;PASSWORD=XXX).XXX.DBO.XXX     (……..)    SELECT ….. FROM …..    COMMIT TRANSACTIONEND TRYBEGIN CATCH      IF @@TRANCOUNT>0        ROLLBACK         ………END CATCH

 

对于这种问题,是因为:对于大多数 OLE DB 访问接口(包括 SQL Server),必须将隐式或显示事务中的数据修改语句中的 XACT_ABORT 设置为 ON。 唯一不需要该选项的情况是在提供程序支持嵌套事务时。具体参考官方文档:

XACT_ABORT must be set ON for data modification statements in an implicit or explicit transaction against most OLE DB providers, including SQL Server. The only case where this option is not required is if the provider supports nested transactions.”

在存储过程里面的BEGIN TRANSACTION前设置SET XACT_ABORT ON;后问题即可解决。

参考资料:

https://docs.microsoft.com/zh-cn/sql/t-sql/statements/set-xact-abort-transact-sql?view=sql-server-2017

SQL Server 2016 配置链接服务器及数据还原【图文】_高文龙_51CTO博客

mikel阅读(912)

来源: SQL Server 2016 配置链接服务器及数据还原【图文】_高文龙_51CTO博客

SQL Server 2016 配置链接服务器及数据还原

说到SQL Server的管理,管理员应该是非常有压力的,需要对数据进行备份及监控,当然备份就比较简单了,通过SSMS创建计划任务就可以对指定的数据库进行定期备份了,但是有的时候需要对数据库中指定的数据进行恢复,也需要了解一定的知识才可以,比如通过SQL的FULL备份还原指定一张表,那如何做呢,当然有很多工具可以完成,但是如果通过SSMS进行管理操作呢,今天我们就说说,通过创建链接服务器来还原操作及管理远程服务器。

环境介绍:我们需要通过本地的SSMS管理远程的SQL Server,远程的SQL Server:192.168.5.16。对于我本地来说远程的SQL Server就叫链接服务器。

我们首先在本地的SSMS展开—服务器对象—-链接服务器—-新建链接服务器

我们输入远程SQL Server的IP地址,然后选择服务器类型—SQL Server,根据自己的环境来选择

然后在安全性菜单—-选择建立连接的范式,我们使用远程登录及密码进行验证;

我们需要输入远程SQL Server的登录账户及密码。然后单击确认

此时我们就可以看见远程链接服务器创建成功了,远程链接服务器上的数据库及表信息都可以看见

此时链接服务器就可以用了,具体格式见下:

Select * From [链接服务器名].[远程数据库名].[所有者].[表名]

比如

select * from [192.168.5.16].[DB1].[dbo].info
1.

我们在远程本地插入几条数据(当然也可以通过远程服务器进行插入)

然后在本地查看链接服务器的数据库信息

select * from [192.168.5.16].[DB1].[dbo].info
1.

我们现在需要将远程SQL Server (链接服务器)上的DB1数据库下的INFO表的所有数据拷贝一份到本地SQL Server服务器的DB2数据库下,然后新建一张info表(本地的info表是不存在的,其实叫新建一张表。)。

我们使用下列命令,将链接服务器DB1库下的info表中所有的数据导入到DB2.dbo.info中,

Select * into DB2.dbo.info From [192.168.5.16].[DB1].[dbo].info
1.

刷新后,我们发现DB2这个数据库多了一个表

我们通过查询本地数据确实已经导入成功了。

导入成功后,如果环境需要的话,我们可以将原来的表删除,然后重名即可。

drop tables xxx
———————————–
©著作权归作者所有:来自51CTO博客作者高文龙的原创作品,谢绝转载,否则将追究法律责任
SQL Server 2016 配置链接服务器及数据还原
https://blog.51cto.com/gaowenlong/1868529

如何使用SQL Server链接服务器访问DB2 Server - 寒枫 - 博客园

mikel阅读(1029)

来源: 如何使用SQL Server链接服务器访问DB2 Server – 寒枫 – 博客园

首先,需要安装Microsoft OLE DB Provider for DB2

下载地址:http://download.microsoft.com/download/B/B/2/BB22098A-C071-415F-9269-2EB26CEFB562/DB2OLEDB_CN.exe
安装以后,菜单多出一项:

接下来,运行“数据访问工具”详细进行配置。

假设DB2的配置信息如下所示

可访问的数据库地址:jdbc:db2://10.18.50.149:50000/BPMDB
用户名:db2admin
密码:db2admin

说明下第五步的字符集:

主机 CCSID 可以通过以下命令获悉。

db2 connect to BPMDB user db2admin using db2admin
db2 get db cfg for BPMDB
查询结果:
C:\IBM\BPM\v8.5\db2\BIN>db2 connect to BPMDB user db2admin using db2admin

数据库连接信息

数据库服务器         = DB2/NT64 10.1.1
SQL 授权标识         = DB2ADMIN
本地数据库别名       = BPMDB

C:\IBM\BPM\v8.5\db2\BIN>db2 get db cfg for BPMDB

数据库 BPMDB 的数据库配置

数据库配置发行版级别                                    = 0x0f00
数据库发行版级别                                        = 0x0f00

数据库地域                                              = US
 数据库代码页                                            = 1208
 数据库代码集                                            = UTF-8
数据库国家/地区代码                                     = 1
数据库整理顺序                                          = IDENTITY
备用整理顺序                              (ALT_COLLATE) =
数字兼容性                                              = OFF

PC 代码页,可以通过以下操作获悉。

第12步的字符串是需要用到的。

Provider=DB2OLEDB;User ID=db2admin;Password=db2admin;Initial Catalog=BPMDB;Network Transport Library=TCP;Host CCSID=1208;PC Code Page=936;Network Address=10.18.50.149;Network Port=50000;Package Collection=BPMDB;Process Binary as Character=False;Units of Work=RUW;DBMS Platform=DB2/MVS;Defer Prepare=False;Rowset Cache Size=0;Persist Security Info=True;Connection Pooling=False;Derive Parameters=False;

 

终于到了配置链接服务器的时候了,继续走起。

 

添加成功,下图能看到链接服务器 HEATHERNET

 

测试链接服务器查询数据

查询正常,能显示中文字段。

 

提示:如果第5步字符集配置不当将会导致中文字段名无法显示正常且一直会提示该字段不存在。

 

消息 7339,级别 16,状态 1,第 1 行
OLE DB provider ‘DB2OLEDB’ for linked server ‘HEATHERNET’ returned invalid data for column ‘[HEATHERNET].[BPMDB].[DB2ADMIN].[V_USER_MAPPING].POSITION_NAME’.

以下是配置正确的查询结果

至此,DB2的链接服务器搭建完毕。

SQLServer实现跨库跨服务器访问的方法

mikel阅读(1085)

来源: SQLServer实现跨库跨服务器访问的方法

前言

我们经常会遇到一个数据库要访问另一个数据库,或者一台服务器要访问另一台服务器里面的数据库。 那么这个如何实现的呢? 相信看完这篇文章你就懂了!

同一台服务器跨库访问实现

1. 首先创建两个数据库CrossLibraryTable1,CrossLibraryTable2

–创建CrossLibraryTable1脚本:

  1. use master –打开master数据库,一般的创建语句都在master中执行.
  2. go
  3. if exists (select * from sysdatabases where name=’CrossLibraryTable1′)
  4. drop database CrossLibraryTable1 /*检查有没有这个数据库,如果有就删除它。*/
  5. go
  6. create database CrossLibraryTable1
  7. on primary
  8. (
  9. name=’CrossLibraryTable1_data’, ———— 养成好习惯,数据文件加_data
  10. filename=’F:\代码存放\数据库\CrossLibraryTable1_data.mdf’, ———— 一定要是.mdf的文件,代表主数据文件
  11. size=5mb, –默认数据库大小
  12. maxsize=100mb, –最大容量
  13. filegrowth=1mb –增长量
  14. )
  15. log on
  16. (
  17. name=’CrossLibraryTable1_log’, ———— 养成好习惯,日志文件加_log
  18. filename=’F:\代码存放\数据库\CrossLibraryTable1_log.ldf’, ———— 一定要是.ldf的文件,代表日志文件
  19. size=1mb, –默认数据库大小
  20. filegrowth=10% –增长量
  21. )

–创建CrossLibraryTable2脚本:

  1. use master –打开master数据库,一般的创建语句都在master中执行.
  2. go
  3. if exists (select * from sysdatabases where name=’CrossLibraryTable2′)
  4. drop database CrossLibraryTable2 /*检查有没有这个数据库,如果有就删除它。*/
  5. go
  6. create database CrossLibraryTable2
  7. on primary
  8. (
  9. name=’CrossLibraryTable2_data’, ———— 养成好习惯,数据文件加_data
  10. filename=’F:\代码存放\数据库\CrossLibraryTable2_data.mdf’, ———— 一定要是.mdf的文件,代表主数据文件
  11. size=5mb, –默认数据库大小
  12. maxsize=100mb, –最大容量
  13. filegrowth=1mb –增长量
  14. )
  15. log on
  16. (
  17. name=’CrossLibraryTable2_log’, ———— 养成好习惯,日志文件加_log
  18. filename=’F:\代码存放\数据库\CrossLibraryTable2_log.ldf’, ———— 一定要是.ldf的文件,代表日志文件
  19. size=1mb, –默认数据库大小
  20. filegrowth=10% –增长量
  21. )

然后,执行完脚本后,刷新一下就可以看到刚刚创建的数据库了:

2.接下来在两个数据库里面分别创建一个CrossTest1和一个CrossTest2表用于跨库查询

–创建CrossTest1脚本:

  1. use CrossLibraryTable1
  2. create table CrossTest1(
  3. Id int primary key identity,
  4. Name nvarchar(20)
  5. )

–创建CrossTest2脚本:

  1. use CrossLibraryTable2
  2. create table CrossTest2(
  3. Id int primary key identity,
  4. Name nvarchar(20)
  5. )

表创建好后,我们再添加几条数据进去:

  1. use CrossLibraryTable1
  2. insert into CrossTest1 values(‘跨库1测试数据1’)
  3. insert into CrossTest1 values(‘跨库1测试数据2’)
  4. use CrossLibraryTable2
  5. insert into CrossTest2 values(‘跨库2测试数据1’)
  6. insert into CrossTest2 values(‘跨库2测试数据2’)

切换到CrossLibraryTable1下面查询CrossLibraryTable2的数据可以看到报如下错误

修正代码:

PS:像上面那样是可以进行查询,然而在项目中使用上面的代码格式就会引发一些问题,那什么问题呢?比如另一个数据库的名称改变了,我们就需要把所有用到这个的地方都得改掉,这样就很麻烦,那么有什么解决方案么,使得改一处就好了?当然有,用数据库同义词就可以轻松搞定!

创建同义词步骤如下:

不同服务器跨库访问实现

当数据库在不同服务器上面,用上面的方法就不行了,那如何实现跨服务器访问呢?很简单,看下面↓↓↓

好了,SQL Server跨库跨服务器访问实现就到这了,如果按照步骤一步一步操作的话,相信您也已经实现了,下一篇文章就来谈谈分库分表实现。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对脚本之家的支持。

您可能感兴趣的文章:

  • SQLServer 跨库查询实现方法
  • SQL Server 跨库同步数据
  • MSSQLServer跨服务器连接(远程登录)的示例代码

给现有MVC 项目添加 WebAPI - 小y - 博客园

mikel阅读(902)

来源: 给现有MVC 项目添加 WebAPI – 小y – 博客园

1. 增加一个WebApi Controller, VS 会自动添加相关的引用,主要有System.Web.Http,System.Web.Http.WebHost,System.Net.Http

2. 在App_Start 下创建 WebApiConfig.cs 并注册路由

复制代码
复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web.Http;

namespace Libaray.Web.App_Start
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            // Web API 配置和服务

            // Web API 路由
            config.MapHttpAttributeRoutes();

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
        }
    }
}
复制代码
复制代码

3. 在Global.asax, Application_Start 下添加 WebAPI 配置

复制代码
复制代码
using Libaray.Web.App_Start;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;

namespace Libaray.Web
{
    public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            GlobalConfiguration.Configure(WebApiConfig.Register);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
        }
    }
}
复制代码
复制代码

4. 在第一步添加的WebApi 中填写相应代码,

复制代码
复制代码
using Libaray.Web.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;

namespace Libaray.Web.Controllers
{
    [RoutePrefix("api/SystemUsers")]
    public class SystemUsersController : ApiController
    {
        [HttpGet, Route("GetUserList")]
        public List<UserModel> GetUserModels()
        {
            UserModelService UserBS = new UserModelService();
            return UserBS.FindList(u => u.isActive == true);
        }

        [HttpGet, Route("GetUser")]
        public UserModel GetUserModel(int id = 0)
        {
            if(id != 0)
            {
                UserModelService UserBS = new UserModelService();
                return UserBS.Find(u => u.Id == id);
            }
            else
            {
                return null;
            }
        }

        [HttpPost, Route("Login")]
        public bool Login(string loginId,string password)
        {
            UserModelService UserBS = new UserModelService();
            return UserBS.ValidateLoginInfo(loginId, password);
        }
    }
}


复制代码
复制代码

5. Run the application and call the API. Example: http://localhost:49919/api/SystemUsers/GetUserList

Web API 强势入门指南 - 微软互联网开发支持 - 博客园

mikel阅读(708)

来源: Web API 强势入门指南 – 微软互联网开发支持 – 博客园

Web API是一个比较宽泛的概念。这里我们提到Web API特指ASP.NET Web API。

这篇文章中我们主要介绍Web API的主要功能以及与其他同类型框架的对比,最后通过一些相对复杂的实例展示如何通过Web API构建http服务,同时也展示了Visual Studio构建.net项目的各种强大。

目录

什么是 Web API

官方定义如下,强调两个关键点,即可以对接各种客户端(浏览器,移动设备),构建http服务的框架。

ASP.NET Web API is a framework that makes it easy to build HTTP services that reach a broad range of clients, including browsers and mobile devices. ASP.NET Web API is an ideal platform for building RESTful applications on the .NET Framework.

Web API在ASP.NET完整框架中地位如下图,与SignalR一起同为构建Service的框架。Web API负责构建http常规服务,而SingalR主要负责的是构建实时服务,例如股票,聊天室,在线游戏等实时性要求比较高的服务。

Picture20

 

为什么要用 Web API

Web API最重要的是可以构建面向各种客户端的服务。另外与WCF REST Service不同在于,Web API利用Http协议的各个方面来表达服务(例如 URI/request response header/caching/versioning/content format),因此就省掉很多配置。

Picture2

 

当你遇到以下这些情况的时候,就可以考虑使用Web API了。

  • 需要Web Service但是不需要SOAP
  • 需要在已有的WCF服务基础上建立non-soap-based http服务
  • 只想发布一些简单的Http服务,不想使用相对复杂的WCF配置
  • 发布的服务可能会被带宽受限的设备访问
  • 希望使用开源框架,关键时候可以自己调试或者自定义一下框架

功能简介

Web API的主要功能

1. 支持基于Http verb (GET, POST, PUT, DELETE)的CRUD (create, retrieve, update, delete)操作

通过不同的http动作表达不同的含义,这样就不需要暴露多个API来支持这些基本操作。

2. 请求的回复通过Http Status Code表达不同含义,并且客户端可以通过Accept header来与服务器协商格式,例如你希望服务器返回JSON格式还是XML格式。

3. 请求的回复格式支持 JSON,XML,并且可以扩展添加其他格式。

4. 原生支持OData

5. 支持Self-host或者IIS host。

6. 支持大多数MVC功能,例如Routing/Controller/Action Result/Filter/Model Builder/IOC Container/Dependency Injection。

Web API vs MVC

你可能会觉得Web API 与MVC很类似,他们有哪些不同之处呢?先上图,这就是他们最大的不同之处。

Picture1

详细点说他们的区别,

  • MVC主要用来构建网站,既关心数据也关心页面展示,而Web API只关注数据
  • Web API支持格式协商,客户端可以通过Accept header通知服务器期望的格式
  • Web API支持Self Host,MVC目前不支持
  • Web API通过不同的http verb表达不同的动作(CRUD),MVC则通过Action名字表达动作
  • Web API内建于ASP.NET System.Web.Http命名空间下,MVC位于System.Web.Mvc命名空间下,因此model binding/filter/routing等功能有所不同
  • 最后,Web API非常适合构建移动客户端服务

Web API vs WCF

发布服务在Web API和WCF之间该如何取舍呢?这里提供些简单地判断规则,

  • 如果服务需要支持One Way Messaging/Message Queue/Duplex Communication,选择WCF
  • 如果服务需要在TCP/Named Pipes/UDP (wcf 4.5),选择WCF
  • 如果服务需要在http协议上,并且希望利用http协议的各种功能,选择Web API
  • 如果服务需要被各种客户端(特别是移动客户端)调用,选择Web API

Web API 实战 (Web API + MongoDB + knockoutjs)

ASP.NET网站上有很多简单的Web API实例,看看贴图和实例代码你就明白怎么用了。这里我们通过一个稍微复杂一点的实例来展示下Web API的功能。

涉及技术

在我们的实例里面用到了:

服务URI Pattern

Action Http verb URI
Get contact list GET /api/contacts
Get filtered contacts GET /api/contacts?$top=2
Get contact by ID GET /api/contacts/id
Create new contact POST /api/contacts
Update a contact PUT /api/contacts/id
Delete a contact DELETE /api/contacts/id

准备工作

1. 下载并安装Mongo DB,步骤看这里

2. Mongo DB C# driver下载可以在nuget搜索mongocsharpdriver。

3. 如果想本地察看数据库中内容,下载MongoVUE

4. Knockoutjs下载可以在nuget搜索knockoutjs。

代码实现

1. 创建项目

创建MVC4 Web Application

1

在Project Template中选择Web API

2

然后项目就创建成了,Controllers里面有一个ValuesController,是自动生成的一个最简单的Web API Controller。

正如我们前面所说,里面引用的是System.Web.Http命名空间。

3

2. 创建model

在model里面添加Contact类

4

代码如下,其中BsonId需要mongocsharpdriver。

1
2
3
4
5
6
7
8
9
public class Contact
    {
        [BsonId]
        public string Id { get; set; }
        public string Name { get; set; }
        public string Phone { get; set; }
        public string Email { get; set; }
        public DateTime LastModified { get; set; }
    }

我们需要添加mongosharpdriver。

7

8

另外我们需要在Model中添加Repository,Controller通过该类来访问Mongo DB。

1
2
3
4
5
6
7
public interface IContactRepository {
        IEnumerable GetAllContacts();
        Contact GetContact(string id);
        Contact AddContact(Contact item);
        bool RemoveContact(string id);
        bool UpdateContact(string id, Contact item);  
    }

ContactRepository的完整实现如下,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
public class ContactRepository : IContactRepository
    {
        MongoServer _server = null;
        MongoDatabase _database = null;
        MongoCollection _contacts = null;
        public ContactRepository(string connection)
        {
            if (string.IsNullOrWhiteSpace(connection))
            {
                connection = "mongodb://localhost:27017";
            }
            _server = new MongoClient(connection).GetServer();
            _database = _server.GetDatabase("Contacts");
            _contacts = _database.GetCollection("contacts");
            // Reset database and add some default entries
            _contacts.RemoveAll();
            for (int index = 1; index < 5; index++)
            {
                Contact contact1 = new Contact
                {
                    Email = string.Format("test{0}@example.com", index),
                    Name = string.Format("test{0}", index),
                    Phone = string.Format("{0}{0}{0} {0}{0}{0} {0}{0}{0}{0}", index)
                };
                AddContact(contact1);
            }
        }
        public IEnumerable GetAllContacts()
        {
            return _contacts.FindAll();
        }
        public Contact GetContact(string id)
        {
            IMongoQuery query = Query.EQ("_id", id);
            return _contacts.Find(query).FirstOrDefault();
        }
        public Contact AddContact(Contact item)
        {
            item.Id = ObjectId.GenerateNewId().ToString();
            item.LastModified = DateTime.UtcNow;
            _contacts.Insert(item);
            return item;
        }
        public bool RemoveContact(string id)
        {
            IMongoQuery query = Query.EQ("_id", id);
            WriteConcernResult result = _contacts.Remove(query);
            return result.DocumentsAffected == 1;
        }
        public bool UpdateContact(string id, Contact item)
        {
            IMongoQuery query = Query.EQ("_id", id);
            item.LastModified = DateTime.UtcNow;
            IMongoUpdate update = Update
                .Set("Email", item.Email)
                .Set("LastModified", DateTime.UtcNow)
                .Set("Name", item.Name)
                .Set("Phone", item.Phone);
            WriteConcernResult result = _contacts.Update(query, update);
            return result.UpdatedExisting;
        }
    }

3. 添加Controller

右键Controllers目录选择添加Controller

5

选择Empty API controller,将Controller命名为ContactsController

6

添加如下代码,可以看到Controller中的API方法名就是以http verb命名的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public class ContactsController : ApiController
    {
        private static readonly IContactRepository _contacts = new ContactRepository(string.Empty);
        public IQueryable Get()
        {
            return _contacts.GetAllContacts().AsQueryable();
        }
        public Contact Get(string id)
        {
            Contact contact = _contacts.GetContact(id);
            if (contact == null)
            {
                throw new HttpResponseException(HttpStatusCode.NotFound);
            }
            return contact;
        }
        public Contact Post(Contact value)
        {
            Contact contact = _contacts.AddContact(value);
            return contact;
        }
        public void Put(string id, Contact value)
        {
            if (!_contacts.UpdateContact(id, value))
            {
                throw new HttpResponseException(HttpStatusCode.NotFound);
            }
        }
        public void Delete(string id)
        {
            if (!_contacts.RemoveContact(id))
            {
                throw new HttpResponseException(HttpStatusCode.NotFound);
            }
        }
    }

4. 添加View

首先添加Knockoutjs库,

9

Knockoutjs通过MVVM模式来实现动态html绑定数据,如下图,其中View-Model是客户端的JavaScript object保存的model数据。

webapi_ef16

先打开HomeController,里面添加一个新的Action代码如下,因为我们要在MVC中对于ContactsController添加对应的View。

1
2
3
4
5
6
7
public ActionResult Admin()
        {
            string apiUri = Url.HttpRouteUrl("DefaultApi", new { controller = "contacts", });
            ViewBag.ApiUrl = new Uri(Request.Url, apiUri).AbsoluteUri.ToString();
            return View();
        }

然后右键Admin方法,选择添加View

10

选择Create strongly-typed view,在model class中选择Contact类。

11

添加View的完整代码,注意view中我们通过js去访问WebAPI,以及通过动态绑定将数据呈现在网页上。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
@model WebAPIDemo.Models.Contact
@{
    ViewBag.Title = "Admin";
}
@section Scripts {
  @Scripts.Render("~/bundles/JQueryval")
  <script type="text/JavaScript" src="@Url.Content("~/Scripts/knockout-2.3.0.js")"></script>
  <script type="text/JavaScript">
      function ProductsViewModel() {
          var self = this;
          self.products = ko.observableArray();
          var baseUri = '@ViewBag.ApiUrl';
          self.create = function (formElement) {
              // If valid, post the serialized form data to the web api
              $(formElement).validate();
              if ($(formElement).valid()) {
                  $.post(baseUri, $(formElement).serialize(), null, "json")
                      .done(function (o) { self.products.push(o); });
              }
          }
          self.update = function (product) {
              $.ajax({ type: "PUT", url: baseUri + '/' + product.Id, data: product });
          }
          self.remove = function (product) {
              // First remove from the server, then from the UI
              $.ajax({ type: "DELETE", url: baseUri + '/' + product.Id })
                  .done(function () { self.products.remove(product); });
          }
          $.getJSON(baseUri, self.products);
      }
      $(document).ready(function () {
          ko.applyBindings(new ProductsViewModel());
      })
  </script>
}
<h2>Admin</h2>
<div class="content">
    <div class="float-left">
    <ul id="update-products" data-bind="foreach: products">
        <li>
            <div>
                <div class="item">ID</div> <span data-bind="text: $data.Id"></span>
            </div>
            <div>
                <div class="item">Name</div>
                <input type="text" data-bind="value: $data.Name"/>
            </div>
            <div>
                <div class="item">Phone</div>
                <input type="text" data-bind="value: $data.Phone"/>
            </div>
            <div>
                <div class="item">Email</div>
                <input type="text" data-bind="value: $data.Email"/>
            </div>
            <div>
                <div class="item">Last Modified</div> <span data-bind="text: $data.LastModified"></span>
            </div>
            <div>
                <input type="button" value="Update" data-bind="click: $root.update"/>
                <input type="button" value="Delete Item" data-bind="click: $root.remove"/>
            </div>
        </li>
    </ul>
    </div>
    <div class="float-right">
    <h2>Add New Product</h2>
    <form id="addProduct" data-bind="submit: create">
        @Html.ValidationSummary(true)
        <fieldset>
            <legend>Contact</legend>
            @Html.EditorForModel()
            <p>
                <input type="submit" value="Save" />
            </p>
        </fieldset>
    </form>
    </div>
</div>

接下来在_layout.cshtml中添加一个admin页面的链接如下

1
2
3
4
5
6
<ul id="menu">
    <li>@Html.ActionLink("Home", "Index", "Home", new { area = "" }, null)</li>
    <li>@Html.ActionLink("API", "Index", "Help", new { area = "" }, null)</li>
    <li>@Html.ActionLink("Admin", "Admin", "Home")</li>
</ul>

5. 测试与调试

大功告成,直接运行下我们的作品,我们的admin链接也显示在右上角,

12

Admin页面的样子,Contact list是动态加载进来的,可以通过这个页面做添加,修改,删除的操作。

13

通过IE network capture来查看请求内容,

重新加载页面,可以看到回复的格式为JSON,

14

JSON内容就是我们mock的一些数据。

image

接下来我们修改,删除,又添加了一条记录,可以看到使用了不同的http method。

image

通过前面安装的mongovue来查看下DB种的数据,先添加的user也在其中,令我感到欣慰。。。

image

其实还有两个有趣的实例,不过文章一写就长了,不好意思耽误大家时间,只好先放放,以后再写。

一步一步使用ABP框架搭建正式项目系列教程 - tkbSimplest - 博客园

mikel阅读(744)

来源: 一步一步使用ABP框架搭建正式项目系列教程 – tkbSimplest – 博客园

研究ABP框架好多天了,第一次看到这个框架的名称到现在已经很久了,但由于当时内功有限,看不太懂,所以就只是大概记住了ABP这个名字。最近几天,看到了园友@阳光铭睿的系列ABP教程,又点燃了我内心要研究ABP框架的熊熊烈火。@阳光铭睿的系列ABP教程我已经看完了,并且ABP官网(http://www.aspnetboilerplate.com/)的文档也看得差不多了。同时也发现了园友@阳光铭睿的系列ABP教程很多都是从官网翻译过来的,而且翻译水平有限,很难不让对英语稍微感兴趣的我挑刺儿(可能@阳光铭睿兄太忙吧),嘿嘿,还望@阳光铭睿兄见谅啊!同时,也看见了很多园友都希望用有园友能使用这个框架做一个项目Demo(其实官网也有Demo,感觉稍微简单点儿)。而我现在要着手一个新的项目,也打算用这个框架,所以想要将我一步一步用这个框架的做项目的步骤和想法跟大家分享出来。但提前声明,我不会将源码分享出来,一是因为这是个正式项目,涉及公司隐私等保密协议;二是因为衷心希望提高.Net开发人员的动手能力,不培养“伸手党”,提高.Net生态圈“保(程)卫(序)者(员)”的素质。但是,有任何问题,我会更大家一起在评论区互动。在此,先谢谢大家的支持!

帮助你学习的广告:关于ABP框架的中文“理论”教程你可以查看ABP理论典藏版,如果您英文好一些的话,那么我建议您去官网阅读英文文档【建议程序员们一定好好学英语,可以获取很多高级技术的一手资料,否则您对技术的掌握和理解就只能取决于翻译者的水平了】

系列教程会按以下顺序展开,很可能会有所变动,以下只是类似一个大纲(也是使用ABP框架创建应用的建议步骤),具体请以具体文章为主!

1.使用boilerplate模版创建解决方案

2.创建实体类

3.创建DbContext

4.创建数据库迁移

5.定义仓储

6.实现仓储

7.构建应用层服务

8.数据校验

9.构建Web API服务

10.开发UI层

11.本土化

12.单元测试

13.总结

ABP理论基础学习,请移步至ABP框架理论研究总结(典藏版)

要学习Module-Zero,请移步至《Module-Zero 学习目录》

织梦DEDECMS转WordPress的教程方法汇总 - 奶爸建站笔记

mikel阅读(870)

来源: 织梦DEDECMS转WordPress的教程方法汇总 – 奶爸建站笔记

织梦DEDECMS转WordPress的教程方法汇总

织梦dedecms是很多站长使用的国产CMS系统之一,近日织梦官方发表通知称商业用户需要购买授权费才能使用,费用为5800元/年,所以商用的站长最好更换掉其他免费开源的建站系统,例如WordPress,或者购买商业授权,毕竟国内的版权已经越来越严格了。

这里奶爸给大家总结几个可以方便把DedeCMS转移到WordPress系统的方法

DedeCMS转WordPress方法一:通过RSS导出然后导入

这个方法的原理很简单,首先,在DedeCMS系统里面把全站的内容都导出为RSS格式,然后利用WordPress的导入功能,导入rss文件,就可以自动把之前的文章复制过来。

具体的大家可以参考下面这个步骤:

https://github.com/zyfcjtc/dedecms_to_wordpress

  1. 在dedecms的dede文件夹(后台文件夹)下找到makehtml_rss_action.php文件,对其进行编辑,找到代码:
    echo "完成所有文件更新!";

    在其下面添加代码:

    echo "<a href='/rss.xml' target='_blank'>浏览…</a>";

    作用是在生成rss.xml文件后方便点击查看生成结果。

  2. 在dedecms的include文件夹下找到arc.rssview.class.php文件,并对其进行编辑,找到代码:
    $murl = $GLOBALS['cfg_cmspath']."/data/rss/".$this->TypeID.".xml";

    修改为:

    $murl = $GLOBALS['cfg_cmspath']."/rss.xml";

    作用是修改生成的rss.xml文件路径,让该文件保存在网站根目录

    再向下找到以下代码并将其删除:

    $orwhere .= "And (arc.typeid in (".GetSonIds($this->TypeID,$this->TypeFields['channeltype']).") )";

进入后台——生成——更新RSS文件,把“单个类目最大记录数”改为全站的文章数量,然后点击“开始更新”,更新完成后,网站根目录下会生成一个全站rss.xml文件,可通过 http://网站域名/rss.xml 查看。 附:如果生成的rss.xml文件有错误,在根目录下的templets文件夹中的plus文件夹里找到rss.htm文件,对其进行编辑,找到代码:

<description><![CDATA[[field:description function='html2text(@me)'/]]]></description>

修改为:

<description><![CDATA[[field:description/]]]></description>

注:wordpress的编码是utf8,如果dedecms使用的不是utf8的,导入前请先转换编码为utf8。 具体如何查看: 找到common.inc.php文件,里面的

$cfg_version = 'V57_UTF8_SP2';
$cfg_soft_lang = 'utf-8';
$cfg_soft_public = 'base';

即可知道是什么编码

导入织梦RSS步骤

  1. 织梦DedeCMS文章标题等基本数据导入wordpress站点 进入wordpress后台admin => 工具 => 导入 => RSS, 上传导入生成的织梦全站RSS文件。 导入过程中有可能会超时,重新上传RSS即可,不会重复导入。 注:我通过修改rss-import.php里的get_posts function,实现了同时导入织梦文章id到wordpress. 具体请见这里: https://github.com/zyfcjtc/dedecms_to_wordpress/blob/main/get_posts.php
  2. 导入织梦CMS文章全文到wordpress站点 织梦文章的数据存储在dede_addonarticle数据库的body字段中,现在需要把body字段的内容转到wordpress数据库的wp_posts数据库的 post_content字段里。这个转换需要使用一个桥梁——那就是dede_archives数据表,即dede_addonarticle上body的内容先转到dede_archives上,再从 dede_archives转到wp_posts的post_content里。这两次转换的匹配点,分别是织梦里的文章id,以及Wordpress里已经导入了的文章标题 (这与织梦里的文章标题是一样的)。具体步骤如下: 进入phpmyadmin,选择dedecms网站使用的数据库,在SQL输入框中执行以下SQL语句,在织梦数据库的dede_archives表上,添加字段body
    ALTER TABLE dede_archives ADD body longtext NOT NULL

    然后再执行以下SQL语句把dede_addonarticle数据表中的body字段内容导入到dede_archives的body字段,语句以dede_addonarticle的aid 和dede_archives的id为匹配点:

    UPDATE dede_archives,dede_addonarticle
    SET dede_archives.body = dede_addonarticle.body  
    WHERE dede_archives.id = dede_addonarticle.aid

    接着通过phpmyadmin导出功能把dede_archives数据表导出,然后再通过导入功能把该数据表导入wordpress网站使用的数据库中,使其与 wp_posts数据库处在同一个数据库里。

    下面再次使用SQL语句把dede_archives的body导入到wp_posts上的post_content上,以文章标题为匹配点(前提是文章标题都是唯一的) 以ID为匹配点:

    UPDATE wp_posts,dede_archives  
    SET wp_posts.post_content = dede_archives.body  
    WHERE wp_posts.id = dede_archives.id

    至此文章内容部分转换完成!

DedeCMS转WordPress方法二:数据库转换

大概思路就是把dedecms的数据库内容导入到wordpress,并且通过一些数据库命令操作,让本来dedecms的数据库转变为wordpress的,这个方法网上的教程都比较老,不推荐尝试。

DedeCMS转WordPress方法三:复制或者采集

这个方法相对来说是奶爸推荐大家操作的,因为最保险,只不过原网站数据量太大的话,操作起来非常费时间。

具体步骤:

  1. 先搭建一个临时的WordPress网站,教程参考:安装WordPress教程
  2. 在WordPress后台,文章,文章分类里面设置好原网站(DEDECMS)的分类。
  3. 手动一篇文章一篇文章的复制或者使用采集软件(淘宝有帮忙写采集规则的店铺),把文章全部采集过来。
  4. 利用elementor这类型的构建器设计网站首页的效果。
  5. 域名切换为原dedecms网站的域名。
  6. 设置伪静态和301跳转规则,实现可以通过老网站的url跳转到新的url,减少SEO影响。

织梦转为WordPress后的注意事项

一、注意做伪静态和301跳转

虽然织梦和WordPress都是php的程序,但是他们的伪静态规则是不一样的,所以从dedecms转到WordPress之后,之前dedecms的文章页链接打开会报错,这就需要自己做301跳转规则来实现老dedecms网站的文章链接跳转到新WordPress网站的链接。

WordPress做301跳转的话也可以使用插件帮忙,例如Redirection

二、网站页面需要重新设计

不管用哪种方法把DEDECMS转换到WordPress,网站的页面设计都会发生变化的,所以网站文章全部复制过来之后,也需要自己从零开始设计网站的页面。新手的话推荐使用elementor构建器操作,或者直接花钱找人帮你设计,这是比较靠谱的方法。

12306抢票算法居然被曝光了!!!居然是redis实现的 - 程序员小饭 - 博客园

mikel阅读(688)

来源: 12306抢票算法居然被曝光了!!!居然是redis实现的 – 程序员小饭 – 博客园

导读

相信大家应该都有抢火车票的经验,每年年底,这都是一场盛宴。然而你有没有想过抢火车票这个算法是怎么实现的呢? 应该没有吧,咱们今天就来一一探讨。其实并没有你想的那么难

bitmap与位运算

redis的bitmap基本使用咱们之前已经介绍过了,如果不是很熟悉的朋友可以看看这里 redis bitmap的基本操作和应用

今天在这里咱们主要是先回顾一下位运算

12306抢票算法详解

我们以北京到西安这趟高铁为例,比如我的路线就是从北京到西安,车上如果只剩最后一张票了,那么如果有其他人,在北京到西安这条路线之间买任何一站,那么我都是买不了票的,换句话说,对于单个座位来说,必须是起点到目的地之间的所有站,都没有人买的话,那么才能被算是有票状态。

所以我们可以尝试用bitmap结合上位操作来实现这种场景,以上述北京到西安为例,我们把问题简化

  • 比如一个火车上只有4个座位
  • 北京到西安,一共是4站,其实是三个区间的,分别为北京->石家庄,石家庄->郑州,郑州->西安

首先我们给每个区间构建一个空位图(0为有票,1为无票)

接下来,比如有人买了一张从北京到西安的票

买票这个动作,比如被分配到的座位是编号为1的座位,那么我们直接把北京到西安的所有站,1号座位全部设置为1,如下图

接下来又有人买了一张从石家庄到西安的票

比如这次分配的是座位2,那么我们把石家庄到西安的所有票全部设置为1就行了,如下图

如何知道还剩几张票?

其实解决这个问题很简单,我们直接把上述位图做一个或操作就可以了

或操作结果有几个0,则说明还剩几张票。

总结

其实解决这个问题主要在于位图的构建,因为火车票对于某一个座位来说,只要起点到终点中间某一个区间被占用了(置为1),那么整个座位都是无效的这个特点,很容易想到用或操作的结果来判断买票结果,我们这里只用了4位是为了方便说明问题,实际中应该是火车上有多少座位,位图的长度就应该是多少。 好了,关于抢票算法我们就介绍到这里,你有没有Get到呢?或者你有没有更好的实现方法呢?