thinkphp--time()&&date()

time()在PHP中是得到一个数字,这个数字表示从1970-01-01到现在共走了多少秒,很奇怪吧
不过这样方便计算,

要找出前一天的时间就是 time()-606024;
要找出前一年的时间就是 time()606024365

那么如何把这个数字换成日期格式呢,就要用到date函数了

$t=time();
echo date(“Y-m-d H:i:s”,$t); //date(‘w’)

第一个参数的格式分别表示:
a - “am” 或是 “pm”
A - “AM” 或是 “PM”
d - 几日,二位数字,若不足二位则前面补零; 如: “01” 至 “31”
D - 星期几,三个英文字母; 如: “Fri”
F - 月份,英文全名; 如: “January”
h - 12 小时制的小时; 如: “01” 至 “12”
H - 24 小时制的小时; 如: “00” 至 “23”
g - 12 小时制的小时,不足二位不补零; 如: “1” 至 12”
G - 24 小时制的小时,不足二位不补零; 如: “0” 至 “23”
i - 分钟; 如: “00” 至 “59”
j - 几日,二位数字,若不足二位不补零; 如: “1” 至 “31”
l - 星期几,英文全名; 如: “Friday”
m - 月份,二位数字,若不足二位则在前面补零; 如: “01” 至 “12”
n - 月份,二位数字,若不足二位则不补零; 如: “1” 至 “12”
M - 月份,三个英文字母; 如: “Jan”
s - 秒; 如: “00” 至 “59”
S - 字尾加英文序数,二个英文字母; 如: “th”,”nd”
t - 指定月份的天数; 如: “28” 至 “31”
U - 总秒数
w - 数字型的星期几,如: “0” (星期日) 至 “6” (星期六)
Y - 年,四位数字; 如: “1999”
y - 年,二位数字; 如: “99”
z - 一年中的第几天; 如: “0” 至 “365”
其它不在上列的字符则直接列出该字符

 

转自 http://www.thinkphp.cn/topic/9355.html

(一)简单的wpf登陆页面

本学期末的大作业是实现一个简单的地铁售票系统。自己带着几个组员便根据老师的要求开始做,有组员负责设计简单的页面,然后由我对页面进行简单的美化,并实现前后台逻辑。此系列博客将根据情况逐步更新项目进度。

先看页面效果:

wpf_login

页面的背景是一张图片,顶端的Login 是一个lable,下方分别是2个textbox,2个button,1个textBlock中嵌套一个hyperlink.

1.当双击双击输入框时,会自动清除框内文字

2.点击Cancel,自动退出项目

3.点击OK,校验并登陆

4.元素居中显示,并自动适应当前屏幕

页面xaml文件代码:

<Window x:Class=”subway.MainWindow”
xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation
xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml
xmlns:d=”http://schemas.microsoft.com/expression/blend/2008
xmlns:mc=”http://schemas.openxmlformats.org/markup-compatibility/2006
xmlns:local=”clr-namespace:subway”
mc:Ignorable=”d”
Title=”MainWindow” Margin=”0” Height=”1478.562” Width=”3010.497” WindowState=”Maximized”>
<Window.Background>
<ImageBrush ImageSource=”Image/login_bg.jpg”/>
</Window.Background>
<Viewbox>
<Grid Height=”591” Width=”1022”>
<!–<Grid.Background>
<ImageBrush ImageSource=”/Image/login_bg.jpg” />
</Grid.Background>–>

    &lt;Label x:Name="label" Content="Login" Foreground="White" Margin="122,43,136,0" VerticalAlignment="Top" FontFamily="微软雅黑" FontSize="45px"  HorizontalContentAlignment="Center" /&gt;
    &lt;TextBox x:Name="textBox_username" Margin="374,163,382,380" TextWrapping="Wrap" Text="username"  Opacity="0.5"  FontFamily="微软雅黑" FontSize="25px" /&gt;
    &lt;PasswordBox x:Name="passwordBox_password" Password="********" Margin="374,232,382,314"    Opacity="0.5" FontFamily="微软雅黑" FontSize="25px" ToolTip="please  input your password"/&gt;
    &lt;Button x:Name="button" IsDefault="True" Content="OK" HorizontalAlignment="Left" Margin="370,335,0,0" VerticalAlignment="Top" Width="94" Height="41" Opacity="0.7" FontFamily="微软雅黑" FontSize="20px" Click="button_Click" &gt;
        &lt;Button.Template&gt;
            &lt;ControlTemplate TargetType="{x:Type Button}"&gt;
                &lt;Border BorderBrush="{TemplateBinding Control.BorderBrush}" BorderThickness="0" CornerRadius="8,8,8,8" Name="PART_Background"&gt;
                    &lt;Border.Background&gt;
                        &lt;LinearGradientBrush EndPoint="0,1" StartPoint="0,0"&gt;
                            &lt;GradientStop Color="White" Offset="0.0" /&gt;
                            &lt;GradientStop Color="Silver" Offset="0.5" /&gt;
                            &lt;GradientStop Color="White" Offset="0.0" /&gt;
                        &lt;/LinearGradientBrush&gt;
                    &lt;/Border.Background&gt;
                    &lt;ContentPresenter Content="{TemplateBinding ContentControl.Content}" HorizontalAlignment="Center" VerticalAlignment="Center" /&gt;
                &lt;/Border&gt;
                &lt;ControlTemplate.Triggers&gt;
                    &lt;Trigger Property="UIElement.IsMouseOver" Value="True"&gt;
                        &lt;Setter Property="Border.Background" TargetName="PART_Background"&gt;
                            &lt;Setter.Value&gt;
                                &lt;LinearGradientBrush EndPoint="0,1" StartPoint="0,0"&gt;
                                    &lt;GradientStop Color="Silver" Offset="0.0" /&gt;
                                    &lt;GradientStop Color="White" Offset="0.5" /&gt;
                                    &lt;GradientStop Color="Silver" Offset="0.0" /&gt;
                                &lt;/LinearGradientBrush&gt;
                            &lt;/Setter.Value&gt;
                        &lt;/Setter&gt;
                    &lt;/Trigger&gt;
                    &lt;Trigger Property="ButtonBase.IsPressed" Value="True"&gt;
                        &lt;Setter Property="UIElement.Effect"&gt;
                            &lt;Setter.Value&gt;
                                &lt;DropShadowEffect BlurRadius="10" Color="Black" Direction="0" Opacity="0.6" RenderingBias="Performance" ShadowDepth="0" /&gt;
                            &lt;/Setter.Value&gt;
                        &lt;/Setter&gt;
                    &lt;/Trigger&gt;
                &lt;/ControlTemplate.Triggers&gt;
            &lt;/ControlTemplate&gt;
        &lt;/Button.Template&gt;
    &lt;/Button&gt;
    &lt;Button x:Name="button1" IsCancel="True" Content="Cancel" HorizontalAlignment="Left" Margin="546,335,0,0" VerticalAlignment="Top" Width="94" Height="41" Opacity="0.7" FontFamily="微软雅黑" FontSize="20px" Click="button1_Click" RenderTransformOrigin="0.553,1.355" &gt;
        &lt;Button.Template&gt;
            &lt;ControlTemplate TargetType="{x:Type Button}"&gt;
                &lt;Border BorderBrush="{TemplateBinding Control.BorderBrush}" BorderThickness="0" CornerRadius="8,8,8,8" Name="PART_Background"&gt;
                    &lt;Border.Background&gt;
                        &lt;LinearGradientBrush EndPoint="0,1" StartPoint="0,0"&gt;
                            &lt;GradientStop Color="White" Offset="0.0" /&gt;
                            &lt;GradientStop Color="Silver" Offset="0.5" /&gt;
                            &lt;GradientStop Color="White" Offset="0.0" /&gt;
                        &lt;/LinearGradientBrush&gt;
                    &lt;/Border.Background&gt;
                    &lt;ContentPresenter Content="{TemplateBinding ContentControl.Content}" HorizontalAlignment="Center" VerticalAlignment="Center" /&gt;
                &lt;/Border&gt;
                &lt;ControlTemplate.Triggers&gt;
                    &lt;Trigger Property="UIElement.IsMouseOver" Value="True"&gt;
                        &lt;Setter Property="Border.Background" TargetName="PART_Background"&gt;
                            &lt;Setter.Value&gt;
                                &lt;LinearGradientBrush EndPoint="0,1" StartPoint="0,0"&gt;
                                    &lt;GradientStop Color="Silver" Offset="0.0" /&gt;
                                    &lt;GradientStop Color="White" Offset="0.5" /&gt;
                                    &lt;GradientStop Color="Silver" Offset="0.0" /&gt;
                                &lt;/LinearGradientBrush&gt;
                            &lt;/Setter.Value&gt;
                        &lt;/Setter&gt;
                    &lt;/Trigger&gt;
                    &lt;Trigger Property="ButtonBase.IsPressed" Value="True"&gt;
                        &lt;Setter Property="UIElement.Effect"&gt;
                            &lt;Setter.Value&gt;
                                &lt;DropShadowEffect BlurRadius="10" Color="Black" Direction="0" Opacity="0.6" RenderingBias="Performance" ShadowDepth="0" /&gt;
                            &lt;/Setter.Value&gt;
                        &lt;/Setter&gt;
                    &lt;/Trigger&gt;
                &lt;/ControlTemplate.Triggers&gt;
            &lt;/ControlTemplate&gt;
        &lt;/Button.Template&gt;
    &lt;/Button&gt;
    &lt;TextBlock  HorizontalAlignment="Left" Margin="576,282,0,0" VerticalAlignment="Top" Foreground="#216380"&gt;
    &lt;Hyperlink NavigateUri="../Admin/Admin_getPassword" Click="Hyperlink_getPWD_Click" &gt;找回密码. . . &lt;/Hyperlink&gt;
    &lt;/TextBlock&gt;
&lt;/Grid&gt;

</Viewbox>



后台逻辑代码:

在构造函数中设置自动适应当前屏幕

       double x = SystemParameters.WorkArea.Width;//得到屏幕工作区域宽度
double y = SystemParameters.WorkArea.Height;//得到屏幕工作区域高度
double x1 = SystemParameters.PrimaryScreenWidth;//得到屏幕整体宽度
double y1 = SystemParameters.PrimaryScreenHeight;//得到屏幕整体高度
this.Width = x1;//设置窗体宽度
this.Height = y1;//设置窗体高度
this.Title = “登陆”;

 

双击输入框

    textBox_username.MouseDoubleClick += BoxMouseDoubleClick;
passwordBox_password.MouseDoubleClick += BoxMouseDoubleClick;
private void BoxMouseDoubleClick(object sender, MouseButtonEventArgs e)
{
passwordBox_password.Password = “”;
textBox_username.Text = “”;
}


 

点击Cancel

this.Close();


点击OK

   /// <summary>
/// 点击OK 实现登陆
/// </summary>
/// <param name=”sender”></param>
/// <param name=”e”></param>
private void button_Click(object sender, RoutedEventArgs e)
{
BaseFunc baseFc = new BaseFunc();
username = textBox_username.Text.Trim();

    string password = passwordBox_password.Password.Trim();
    if(username==""||password=="")
    {
        MessageBox.Show("请输入正确信息");
        return;
    }
    else
    {
        bool isLogin = baseFc.GetLoginCheck(username, password);
        if(isLogin)
        {
            //this.Close();
            // MessageBox.Show("登陆成功");
            chooseSystem chose = new chooseSystem();
            chose.ShowDialog();
        }
        else
        {
            MessageBox.Show("登陆失败,无此用户或信息错误");
        }
    }
    MessageBox.Show(username);

}</code></pre>

找回密码的页面与的登陆相同,后台逻辑在之前的博客中已经写过,邮件不会当作垃圾邮件处理,目前不支持域邮箱。再次贴出代码(包括用户检测,邮件发送)

    #region 密码丢失

/// &lt;summary&gt;
/// 发送密码
/// &lt;/summary&gt;
/// &lt;param name="username"&gt;用户名&lt;/param&gt;
/// &lt;param name="password"&gt;新密码&lt;/param&gt;
/// &lt;returns&gt;&lt;/returns&gt;
public string GetSendpasswrord(string username, string email)
{
    User member = new User();
    if (baseF.GetCheckUser(username))//检查是否已被注册
    {
        try
        {
            SqlConnection conn = connectdb.ConnectDataBase();
            //打开数据库
            conn.Open();
            //创建查询语句
            SqlCommand querySingleInfo = conn.CreateCommand();
                querySingleInfo.CommandText = "SELECT email FROM coustom where UserName=" + "'" + username + "'";
            SqlDataReader singleInfoReader = querySingleInfo.ExecuteReader();
            //有多行数据,用while循环
            while (singleInfoReader.Read())
            {
                member.email = singleInfoReader["email"].ToString().Trim();
            }
            if (member.email.Equals(email))
            {
                string pwd = "你的密码是: ";
                //获取密码
                pwd += Getpassrord(username);
                pwd += " , 请妥善保存";
                //发送邮件
                checkInfo = SendEmail(email, pwd);
            }
            else
            {
                checkInfo = "邮箱错误";
            }
        }
        catch (SqlException e)
        {
            Console.WriteLine("查询错误");
            checkInfo = "查询错误";
        }
    }
    else
        checkInfo = "用户名不存在";
    return checkInfo;
}

/// &lt;summary&gt;
/// 获取用户密码
/// &lt;/summary&gt;
/// &lt;param name="username"&gt;用户名&lt;/param&gt;
/// &lt;returns&gt;返回查询结果&lt;/returns&gt;
private string Getpassrord(string username)
{
    string password = "";
    try
    {
        SqlConnection conn = connectdb.ConnectDataBase();
        //打开数据库
        conn.Open();
        //创建查询语句
        SqlCommand querySingleInfo = conn.CreateCommand();
            querySingleInfo.CommandText = "SELECT Password FROM coustom where UserName=" + "'" + username + "'";
        SqlDataReader singleInfoReader = querySingleInfo.ExecuteReader();
        //有多行数据,用while循环
        while (singleInfoReader.Read())
        {
            password = singleInfoReader["Password"].ToString().Trim();
        }
        //关闭查询
        singleInfoReader.Close();
        //关闭数据库连接
        conn.Close();
    }
    catch (SqlException e)
    {
        password = "查询失败";
    }
    return password;
}

/// &lt;summary&gt;
/// 发送邮件
/// &lt;/summary&gt;
/// &lt;param name="email"&gt;邮件&lt;/param&gt;
/// &lt;param name="password"&gt;授权码&lt;/param&gt;
/// &lt;returns&gt;&lt;/returns&gt;
private string SendEmail(string email, string message)
{
    try
    {
        SmtpClient smtpClient = new SmtpClient();
        smtpClient.EnableSsl = true;
        smtpClient.UseDefaultCredentials = true;
        smtpClient.DeliveryMethod = SmtpDeliveryMethod.Network;//指定电子邮件发送方式        
        smtpClient.Host = "smtp.qq.com";//指定SMTP服务器  (126)    
        System.Net.NetworkCredential nc = new System.Net.NetworkCredential("a@qq.com", "授权码");
        smtpClient.Credentials = nc;//用户名和授权码
        // 发送邮件设置        
        MailMessage mailMessage = new MailMessage("a@qq.com", email); // 发送人和收件人        
        mailMessage.Subject = "密码找回";//主题        
        mailMessage.Body = message;
        mailMessage.BodyEncoding = Encoding.UTF8;//正文编码        
        mailMessage.IsBodyHtml = true;//设置为HTML格式        
        mailMessage.Priority = MailPriority.High;//优先级
        smtpClient.Send(mailMessage);
        sendInfo = "发送成功";
    }
    catch (Exception e)
    {
        sendInfo = e.ToString();
    }
    return sendInfo;
}

#endregion</code></pre>


 

 

slack关联gitlb

slack作为目前团队交流的头号先锋,在我们的项目协调中发挥着很大的作用。其中一项就是实时推送gitlab中的各种动态,此时就需要搭建一个桥梁用来连接,使之实现通讯

 

Slack Service

On Slack

To enable Slack integration you must create an incoming webhook integration on Slack:

  1. Sign in to Slack
  2. Visit Incoming WebHooks
  3. Choose the channel name you want to send notifications to.
  4. Click Add Incoming WebHooks Integration
  5. Copy the Webhook URL, we’ll need this later for GitLab.

On GitLab

After you set up Slack, it’s time to set up GitLab.

Go to your project’s Settings > Services > Slack and you will see a checkbox with the following events that can be triggered:

  • Push
  • Issue
  • Merge request
  • Note
  • Tag push
  • Build
  • Wiki page
    Bellow each of these event checkboxes, you will have an input field to insert which Slack channel you want to send that event message, with #general being the default. Enter your preferred channel without the hash sign (#).

At the end, fill in your Slack details:

Field

Description

Webhook

The incoming webhook URL which you have to setup on Slack.

Username

Optional username which can be on messages sent to slack. Fill this in if you want to change the username of the bot.

Notify only broken builds

If you choose to enable the Build event and you want to be only notified about failed builds.



After you are all done, click Save changes for the changes to take effect.

Note: You can set “branch,pushed,Compare changes” as highlight words on your Slack profile settings, so that you can be aware of new commits when somebody pushes them.
Slack configuration

ThinkPHP实现数据增删改查

提到ThinkPHP,相信大家都有听说,相信很多朋友也都已经会使用,今天还是想写一下关于ThinkPHP的一些基本使用方法,希望对还不会使用的朋友能提供一些帮助!

一、下载ThinkPHP源码包,登录ThinkPHP的官方网站:http://www.thinkphp.cn,在右侧可以看到ThinkPHP源码包的下载,我们这里以3.2.3这个版本进行讲解
图片描述
二、将下载后得到的包复制到你的服务器运行目录下,如果你使用的是Wamp等一些PHP服务器套件,一般就是需要将其复制到WWW目录下。
图片描述
三、这时候在浏览器输入你服务器的访问地址即可成功运行ThinkPHP,例如:http://localhost/thinkphp,运行成功后,会得到如下页面
图片描述
至此,恭喜你已成功安装ThinkPHP。
下面说下最基本的“增删改查”四步操作!
在使用ThinkPHP之前,我们先来了解一下什么是MVC设计模式,MVC即模型-视图-控制器(Model-View-Controller)的简称,我们举个例子,通过这个例子大家也许可以更好的理解MVC。
我们现在想象一个场景,我们在公司上班,我们都会有一个老板,这个老板我们就想象为是控制器,他发话让你去干什么事情,也就是他控制你去干什么事情,具体这件事怎么干他不管,你就可以按照你的方法去做,你做这件事的这个方法就是模型,当你做完这件事后,你把这个事情的结果即视图返回给老板,老板将视图上显示的内容返回给客户。就这么一个过程。下面我们开始数据的增删改查。
一、连接数据库
1、增加数据,当然需要用到数据库,所以我们先建立一个数据库名为thinkphp,然后在这个库里面新建一张数据表thinkusers,至于为什么前面要加上think,我们待会说,在这张表里面添加3个字段,user_id,user_name,user_password,userscore。
<img title=”ThinkPHP实现数据增删改查
“ src=”http://img.mukewang.com/57172a020001de9301650119.png“ alt=”图片描述” />
2、现在需要在Conf文件夹下的Config.php中加入相关数据库配置代码,这里可以看到数据库表前缀,也就是我们之前为什么要在表名前加think_的原因
//数据库配置信息
‘DB_TYPE’ => ‘mysql’, // 数据库类型
‘DB_HOST’ => ‘127.0.0.1’, // 服务器地址
‘DB_NAME’ => ‘thinkphp’, // 数据库名
‘DB_USER’ => ‘root’, // 用户名
‘DB_PWD’ => ‘123456’, // 密码
‘DB_PORT’ => 3306, // 端口
‘DB_PARAMS’ => array(), // 数据库连接参数
‘DBPREFIX’ => ‘think‘, // 数据库表前缀
‘DB_CHARSET’=> ‘utf8’, // 字符集
‘DBDEBUG’ => TRUE, // 数据库调试模式 开启后可以记录SQL日志
3、现在验证下数据库有没有联通,我们在数据库中插入一些数据,如下:
<img title=”ThinkPHP实现数据增删改查
“ src=”http://img.mukewang.com/57172a1d0001ea3606830150.png“ alt=”图片描述” />
现在在Controller文件夹下的IndexController.class.php中加入如下代码:图片描述
此时运行浏览器,如果出现下面的数据显示,表示数据库已经成功连接,如果出现错误提示,请检查一下数据库端口或密码是否配置正确。图片描述
好了,看到这个说明你已经成功连接数据库,并且把数据已经读出来了。
二、增加数据
数据库连接好了之后,我们下一步就是对数据进行添加了。
依旧在刚刚的IndexController.class.php中继续添加代码:图片描述
现在在浏览器输入地址访问这个addData控制器:http://localhost:8888/thinkphp/home/index/adddata,这个地址前面的域名根据你的实际情况进行修改,这时候,页面如果没有报错,空白显示就证明已经成功执行了。现在回到刚刚的数据表,刷新就可以看到刚刚添加的数据,密码这里进行了MD5加密。![图片描述][9]
三、查询数据
其实我们之前已经讲过了,$Users->select();就可以读出表中的所有数据,只是如果我们需要针对相关条件进行筛选这里要怎么做呢,比如我们现在看一下数据表中完整的数据如下:图片描述
现在我们需要读取用户分数大于90分的用户,可以这样写:图片描述
在上面的数据表我们可以看到共有三个用户的分数大于90分,所以执行这段查询代码已经就只会得到三个用户的数据,我们现在运行:http://localhost:8888/thinkphp/home/index/selectscore,得到下图:![图片描述][12]
发现确实只有id为3、4、5的三位用户的数据被查询了出来。
四、修改数据
那么如何修改数据呢,可以这样写:图片描述
这时候运行浏览器输入地址http://localhost:8888/thinkphp/home/index/updatedata,就可以看到user_id为6的用户的数据被修改了。图片描述
五、删除数据
删除也很简单,只需将代码换为:
$Users = M(“Users”); // 实例化Usesr对象
$Users->where(‘user_id=5’)->delete(); // 删除user_id为5的用户数据
这样一运行就可以删除user_id为5的数据了。

本文原创发布于慕课网 ,转载请注明出处,谢谢合作!


作者: 当代码遇上音乐
链接:http://www.imooc.com/article/6747?block_id=tuijian_wz
来源:慕课网
本文原创发布于慕课网 ,转载请注明出处,谢谢合作!

sql server 存储过程入门(二)

指定参数

    通过指定过程参数,调用程序可以将值传递给过程的主体。 在执行过程期间,这些值可以用于各种目的。 如果将参数标记为 OUTPUT 参数,则过程参数还可以将值返回给调用程序。一个过程最多可以有 2100 个参数,每个参数都有名称、数据类型和方向。 还可以为参数指定默认值(可选)。

将值传递给参数

-- 常量 
use LuckyGitlabStats
go
exec GetMember 'webapp',2
-- 变量  类型和创建时保持一致   set赋值,可以用sql server 自带的参数
declare @groupname nchar(100), @rank nchar(10)  --声明变量
set @groupname='webapp';  --变量赋值
set @rank=2
exec GetMember @groupname , @rank   --执行存储过程

指定参数名称、类型

    创建存储过程、声明参数时,参数名称必须以单个@字符开头,并且在过程范围内必须唯一。
    必须使用数据类型定义参数。 参数的数据类型确定了在调用过程时该参数所接受值的类型和范围。
    显式命名参数并将相应的值赋给过程调用中的每个参数允许按任意顺序提供参数。 例如,如果过程 my_proc 应有三个参数,分别命名为 @first、 @second和 @third,则可以将传递到该过程的值赋给参数名称,例如:

EXECUTE my_proc @second = 2, @first = 1, @third = 3;

注意

如果以 @parameter =value 格式提供了一个参数值,则必须按此格式提供所有的后续参数。   
如果未以 @parameter =value 格式传递参数值,则必须按 CREATE PROCEDURE 语句中所列的参数顺序(从左到右)提供值。

指定参数的默认值

    如果在声明参数时指定了默认值,则参数被视为可选的。 在过程调用中不需要为可选参数提供值。
在以下情况下使用参数的默认值:

  1. 在过程调用中未指定参数值。
  2. 在过程调用中将 DEFAULT 关键字指定为值。

    如果没有合适的值可以指定为参数的默认值,则指定 NULL 为默认值。 如果在未提供参数值的情况下执行过程,最好让过程返回自定义的消息。

存储过程GetMember,添加默认值判断

USE [LuckyGitlabStats]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

ALTER PROCEDURE [dbo].[GetMember] 
    -- Add the parameters for the stored procedure here
    @Groupname nchar(100) = null, 
    @Rank nchar(10) = null
AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;
    if @Groupname IS NULL
    begin
        PRINT 'ERROR: You must specify the name of your group.'  
       RETURN  
    end
    -- Insert statements for procedure here
    SELECT * from Member
    where Groupname=@Groupname  and RANK = @Rank
END


-- 执行存储过程
use LuckyGitlabStats
go
--exec GetMember 'webapp' , 2
declare  
    @rank nchar(10),
    @Username nchar(100),
    @groupname nchar(100);
 set @rank=2
 set @groupname='webapp'
EXECUTE  GetMember  'webapp',2 ,@Username  OUTPUT  
select @UserName

--输出   RROR: You must specify the name of your group.

输出参数的方向

    参数的方向可以为输入(表明将值传递给过程的主体),也可以为输出(表明过程将值返回给调用程序)。 默认为输入参数
    若要指定输出参数,必须在 CREATE PROCEDURE 语句的参数定义中指定 OUTPUT 关键字。 当过程退出时,它向调用程序返回输出参数的当前值。 执行过程时,调用程序也必须使用 OUTPUT 关键字,才能将该参数值保存到可以在调用程序中使用的变量中。
给修改上方例子添加一个输出参数 @Username

USE [LuckyGitlabStats]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

ALTER PROCEDURE [dbo].[GetMember] 
    -- Add the parameters for the stored procedure here
    @Groupname nchar(100) = null, 
    @Rank nchar(10) output ,
    @Username nchar(100) OUTPUT
AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;
    if @Groupname IS NULL
    begin
        PRINT 'ERROR: You must specify the last name of the sales person.'  
       RETURN  
    end
    -- Insert statements for procedure here
    SELECT * from Member
    where Groupname=@Groupname and RANK=@Rank

    select @Username = username 
    from Member 
    where Groupname=@Groupname  and RANK=@Rank
    order by UserName desc
END


-- 执行存储过程

go
--exec GetMember 'webapp' , 2
declare -- @rank nchar(10),
     @Username nchar(100);
 -- @groupname nchar(100);

-- set @rank=2
-- set @groupname='webapp'
EXECUTE  GetMember  'webapp',2 ,@Username  OUTPUT  
select @UserName

注意

经测试,一个输出参数,只能返回一个值,当返回一个结果集时,会**按照字典序显示首元素**

C# 获取SQL Server print 结果

static public void ExecuteStoredProc()
{
    var connectionString = @"sql";
    using (var connection = new SqlConnection(connectionString))
    using (var command = new SqlCommand("GetMember", connection))
    {
        command.CommandType = CommandType.StoredProcedure;
        command.Parameters.AddWithValue("@rank", "2");

        connection.Open();
        // wire up an event handler to the connection.InfoMessage event
        connection.InfoMessage += connection_InfoMessage;
        var result = command.ExecuteNonQuery();
        connection.Close();
    }
}

static void connection_InfoMessage(object sender, SqlInfoMessageEventArgs e)
{
    // this gets the print statements (maybe the error statements?)
    var outputFromStoredProcedure = e.Message;
    Console.WriteLine(e.Message);
}

参考

https://docs.microsoft.com/zh-cn/sql/relational-databases/stored-procedures/specify-parameters
《sql的查询艺术》

MS Bot 与LUIS关联

LUIS( Language Understanding Intelligent Service)是微软认知服务的一部分,主要提供语言理解分析交互服务。之前可以通过官网直接把demo搭建到MS Bot和Slack, 现在似乎有点不方便,例如:LUIS关闭了与Slack的直接搭建通道

以下博文来自http://www.c-sharpcorner.com/article/an-interactive-bot-application-with-luis-using-microsoft-bot/ 作者为微软MVP Sourabh Somani

 

Introduction In my previous two articles I have explained how can we create a bot application. In this article I will explain you how can we create our bot application more interactive for our user.s In this article I will use one of the Microsoft Cognitive Services that is LUIS.


My Previous Articles on Bot Framework


Note: Here I am giving My Project link because In this article I will use Real Time Bot Project Using Microsoft Bot Framework article and I will add LUIS in this project.


What is LUIS ? According to luis.ai, LUIS is a Language Understanding Intelligent Service, which offers a fast and effective way of adding language understanding to applications. With LUIS, you can use pre-existing, world-class, pre-built models from Bing and Cortana whenever they suit your purposes and when you need specialized models, LUIS guides you through the process of quickly building them. LUIS is a part of Microsoft Cognitive Service.


Let’s Understand LUIS with an example:

Example 1:
Suppose I search in my Windows 10 PC or Windows phone through Cortana like “Where am I,” then I will get a map and my current location. However I am not saying to Cortana to search for location, I am just saying “Where am I”, And cortana is understanding what am I looking for and this is happening because of LUIS.



Example 2:_ _Suppose I search like Email to contact@sourabhsomani.com then cortana recognizes my command using LUIS and give me result like as follows:



So in above examples you can see there is more interaction.


Let’s look at my previous example In my previous article I created a Real Time Bot Application where I was searching for stock price by stock symbol like as following figure.



In the above figure you can see that message is not more conversational I am just sending input as _msft and getting result but for our users it will not be more interactive.


In this article I will explain to you how can we make our Bot more interactive. Like my input will be “What about msft” or _“What is the price of orcl stock”, Like as following figure:


The above conversation is more interactive, and this can be done by using LUIS.


Let’s create application step by step
**

Step 1: Firstly open visual studio, and create a bot application with any name. Follow following steps to create an Bot application:



1. File > New > Project or just Press CTRL + SHIFT + N.
2. Now for Visual C# template select Bot Application then give the name of the application and then click OK button to create the application.


Step 2: Now go to LUIS Website, then login in to your account or register there. Then After create new application.


Step 3: Now one dialog box will be open; provide Application Name, Description, and Application Culture and then click on Add App Button.




I have created my app by name StockApp.


Step 4: Now edit your application by clicking on Edit button.



Step 5:

On the left-hand panel, you will see an option to add entities. So quickly add an Entity with Name
StockSymbol. Follow following figure to add an entity.





What is Entity:

An entity is a keyword for which we will search like in our example entity is _msft _that is nothing but an Stock Symbol so I have given my entity name StockSymbol.


Step 6:

On the left-hand panel, you will see an option to Add Intents. So le’ts Quickly add Some intents. Give the name of the intents and example of utterance and Save.




I have added two intents StockPrice and StockPrice2. What is Intents? :

Intent means just what we desire and what is our intention so my intention is I would like to ask to my Bot “what about msft” or “what is the price of msft stock”.
What are utterances:

How will I search will be my statements. So I have added 4-5 statements. But after 4-5 LUIS will automatically detect what we want.

>

Step 7: Now add some utterances like as following.



Here you have to define StockSymbol, After doing this for 4-5 LUIS will automatically detect what is our entity.
Note: Don’t forget to add entity by clicking on entity and submiting it after defining entity.


Step 8: Publish your application by clicking on publish button.



Step 9: Now one dialog box will open search there for your query.



Step 10: Hit Enter and you will get JSON format result.


Step 11:

Now again flip to visual studio and create class file for this JSON result. I am addinga few of the classes for this JOSN result. Class code is given below in figure.


>

Well I have just generated this class code using JSON. By Copy and Paste JSON as Classes. Learn How can you paste JSON as Classes.


Step 12:

Now Create a class in your project with any name. I am giving Name as
YahooBot**, Which class Yahoo Finance API to get Stock Information, I am writing the following code inside it.



  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Net;
  5. using System.Threading.Tasks;
  6. using System.Web;
    7.8. namespace StockBot2
  7. {
  8. public class YahooBot
  9. {
  10. public static async Task<double?> GetStockRateAsync(string StockSymbol)
  11. {
  12. try
  13. {
  14. string ServiceURL = $http://finance.yahoo.com/d/quotes.csv?s={StockSymbol}&f=sl1d1nd;
  15. string ResultInCSV;
  16. using (WebClient client = new WebClient())
  17. {
  18. ResultInCSV = await client.DownloadStringTaskAsync(ServiceURL).ConfigureAwait(false);
  19. }
  20. var FirstLine = ResultInCSV.Split(‘\n’)[0];
  21. var Price = FirstLine.Split(‘,’)[1];
  22. if (Price != null && Price.Length >= 0)
  23. {
  24. double result;
  25. if (double.TryParse(Price, out result))
  26. {
  27. return result;
  28. }
  29. }
  30. return null;
  31. }
  32. catch (WebException ex)
  33. {
  34. //handle your exception here
  35. throw ex;
  36. }
  37. }
  38. }
  39. }


In the above code you can see a function that is GetStockRateAsync, which takes a StockSymbol as a parameter. I am calling Yahoo Finance API, where I will pass that symbol and that will return a CSV file of stock market rate, and I am splitting CSV File by commas because CSV File means Comma Separated Value. So, I am splitting by comma(,) and getting current price of that stock. Then I am converting it into double because of course our stock rate will be in double and returning current price.


Step 13: Now in MessagesController create a class that will call this above function., so I am creating a GetStock function in My MessageController class.



  • private async Task<string> GetStock(string StockSymbol)

  • {
  • double? dblStockValue = await YahooBot.GetStockRateAsync(StockSymbol);
  • if(dblStockValue==null)
  • {
  • return string.Format(“This \”{0}\” is not an valid stock symbol”,StockSymbol);
  • }
  • else
  • {
  • return string.Format(“Stock Price of {0} is {1}”,StockSymbol,dblStockValue);
  • }
  • }


  • In above code you can see I am calling my GetStockRateAsync function that will return a nullable double. I am checking whether that stock value is null or not. According to stock value I am returning appropriate string.


    Step 14: As we know we like to interact via LUIS so I am creating one more method in MessagesController with name GetEntityFromLUIS.



  • private static async Task<StockLUIS> GetEntityFromLUIS(string Query)

  • {
  • Query = Uri.EscapeDataString(Query);
  • StockLUIS Data = new StockLUIS();
  • using (HttpClient client=new HttpClient())
  • {
  • string RequestURI = https://api.projectoxford.ai/luis/v1/application?id=7f626790-38d6-4143-9d46-fe85c56a9016&subscription-key=09f80de609fa4698ab4fe5249321d165&q= + Query;
  • HttpResponseMessage msg = await client.GetAsync(RequestURI);
    9.10. if (msg.IsSuccessStatusCode)
  • {
  • var JsonDataResponse = await msg.Content.ReadAsStringAsync();
  • Data = JsonConvert.DeserializeObject<StockLUIS>(JsonDataResponse);
  • }
  • }
  • return Data;
  • }


  • Above code will take query from us and process query using LUIS Service and return StockLUIS class object, That is nothing but JSON data as a class format.


    Step 15: Now write following code in Post Action of Message Controller.



  • public async Task<Message> Post([FromBody]Message message)

  • {
  • if (message.Type == “Message”)
  • {
  • string StockRateString;
  • StockLUIS StLUIS = await GetEntityFromLUIS(message.Text);
  • if(StLUIS.intents.Count()>0)
  • {
  • switch(StLUIS.intents[0].intent)
  • {
  • case “StockPrice”:
  • StockRateString = await GetStock(StLUIS.entities[0].entity);
  • break;
  • case “StockPrice2”:
  • StockRateString = await GetStock(StLUIS.entities[0].entity);
  • break;
  • default:
  • StockRateString = “Sorry, I am not getting you…”;
  • break;
  • }
  • }
  • else
  • {
  • StockRateString = “Sorry, I am not getting you…”;
  • }
    26.27. // return our reply to the user
  • return message.CreateReplyMessage(StockRateString);
  • }
  • else
  • {
  • return HandleSystemMessage(message);
  • }
  • }


  • Above code takes message from Bot User and sends message to LUIS now LUIS will process the message if the message will be identify then send StockLUIS class Object. Now if data will be identified then it will check intents and whatever entity will return LUIS service that will be pass to Yahoo Web Service and we will get string as a result that will be pass to client. If no Intent will be there then we will tell to our client that “Sorry, I am Not Getting You…”.


    Step 16: Now run this project in Emulator.


    Output: If we send wrong query to LUIS then Output will be as follows,

    If we query with invalid stock symbol then output will be as follows,


    Query with valid query and valid stock symbol:




    Suppose in above figure I Forget to provide stock there then also LUIS will give me the accurate result.


    Conclusion:



    In this article we have created an interactive Bot Application with LUIS using Microsoft Bot Framework. We learn about LUIS and its power.
    * We have seen how LUIS helps in powerful interactive Conversation.

    将bot发布到AZURE

    MS Bot 的官方搭建地方是AZURE,访问方式类似于ASP.NET,属于web应用服务只不过需要使用https通讯协议,通过URL进行访问。

    1.在AZURE上创建一个web服务

    [caption id=”attachment_189” align=”alignnone” width=”300”]创建azure web服务 创建azure web服务[/caption]

    2.在vs2015中,右击解决方案名字,然后点击“发布

    3.选择Microsoft Azure app Services,并点击“下一步

    Microsoft Azure App Services

    4.选择订阅号Subscription,在弹窗 弹窗下方的panel中选择和刚才创建的服务(亦可点击NEW进行创建)

    SouthEastAsia

    5.点击Create创建,就可以自动在AZURE上自动创建,该服务就会被发布在页面所提供的url中(在创房间bot服务中会用到此url)

    Microsoft Azure Portal

     

    接下来,一路点击next即可完成发布操作。。。。。。

    如果代码有更新,直接进行发布即可(以上步骤也会自动省略)

    .NET 常用的几种读取XML文件的方法

    转自 http://www.cnblogs.com/xiaoxiangfeizi/archive/2011/07/29/2120807.html

    XML文件是一种常用的文件格式,例如WinForm里面的app.config以及Web程序中的web.config文件,还有许多重要的场所都有它的身影。Xml是Internet环境中跨平台的,依赖于内容的技术,是当前处理结构化文档信息的有力工具。XML是一种简单的数据存储语言,使用一系列简单的标记描述数据,而这些标记可以用方便的方式建立,虽然XML占用的空间比二进制数据要占用更多的空间,但XML极其简单易于掌握和使用。微软也提供了一系列类库来倒帮助我们在应用程序中存储XML文件。

    “在程序中访问进而操作XML文件一般有两种模型,分别是使用DOM(文档对象模型)和流模型,使用DOM的好处在于它允许编辑和更新XML文档,可以随机访问文档中的数据,可以使用XPath查询,但是,DOM的缺点在于它需要一次性的加载整个文档到内存中,对于大型的文档,这会造成资源问题。流模型很好的解决了这个问题,因为它对XML文件的访问采用的是流的概念,也就是说,任何时候在内存中只有当前节点,但它也有它的不足,它是只读的,仅向前的,不能在文档中执行向后导航操作。”具体参见在Visual C#中使用XML指南之读取XML

    下面我将介绍三种常用的读取XML文件的方法。分别是

    1: 使用 XmlDocument
    2: 使用 XmlTextReader
    3: 使用 Linq to Xml
    

    这里我先创建一个XML文件,名为Book.xml下面所有的方法都是基于这个XML文件的,文件内容如下:

    1: <?xml version="1.0" encoding="utf-8"?>
       2: <bookstore>
       3:   <!--记录书本的信息-->
       4:   <book Type="必修课" ISBN="7-111-19149-2">
       5:     <title>数据结构</title>
       6:     <author>严蔚敏</author>
       7:     <price>30.00</price>
       8:   </book>
       9:   <book Type="必修课" ISBN="7-111-19149-3">
      10:     <title>路由型与交换型互联网基础</title>
      11:     <author>程庆梅</author>
      12:     <price>27.00</price>
      13:   </book>
      14:   <book Type="必修课" ISBN="7-111-19149-4">
      15:     <title>计算机硬件技术基础</title>
      16:     <author>李继灿</author>
      17:     <price>25.00</price>
      18:   </book>
      19:   <book Type="必修课" ISBN="7-111-19149-5">
      20:     <title>软件质量保证与管理</title>
      21:     <author>朱少民</author>
      22:     <price>39.00</price>
      23:   </book>
      24:   <book Type="必修课" ISBN="7-111-19149-6">
      25:     <title>算法设计与分析</title>
      26:     <author>王红梅</author>
      27:     <price>23.00</price>
      28:   </book>
      29:   <book Type="选修课" ISBN="7-111-19149-1">
      30:     <title>计算机操作系统</title>
      31:     <author>7-111-19149-1</author>
      32:     <price>28</price>
      33:   </book>
      34: </bookstore>
    

    为了方便读取,我还定义一个书的实体类,名为BookModel,具体内容如下:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace 使用XmlDocument
     {
       public class BookModel
       {
               public BookModel()
               { }
               /// <summary>
               /// 所对应的课程类型
               /// </summary>
               private string bookType;
    
               public string BookType
               {
                   get { return bookType; }
                   set { bookType = value; }
               }
    
               /// <summary>
               /// 书所对应的ISBN号
               /// </summary>
               private string bookISBN;
    
               public string BookISBN
               {
                   get { return bookISBN; }
                   set { bookISBN = value; }
               }
    
               /// <summary>
               /// 书名
               /// </summary>
               private string bookName;
    
               public string BookName
               {
                   get { return bookName; }
                   set { bookName = value; }
               }
    
               /// <summary>
               /// 作者
               /// </summary>
              private string bookAuthor;
    
               public string BookAuthor
               {
                   get { return bookAuthor; }
                   set { bookAuthor = value; }
               }
    
               /// <summary>
               /// 价格
               /// </summary>
               private double bookPrice;
    
               public double BookPrice
               {
                   get { return bookPrice; }
                   set { bookPrice = value; }
               }
           }
       }
    

    1.使用XmlDocument.

    使用XmlDocument是一种基于文档结构模型的方式来读取XML文件.在XML文件中,我们可以把XML看作是由文档声明(Declare),元素(Element),属性(Attribute),文本(Text)等构成的一个树.最开始的一个结点叫作根结点,每个结点都可以有自己的子结点.得到一个结点后,可以通过一系列属性或方法得到这个结点的值或其它的一些属性.例如:

    1: xn 代表一个结点
    2: xn.Name;//这个结点的名称
    3: xn.Value;//这个结点的值
    4: xn.ChildNodes;//这个结点的所有子结点
    5: xn.ParentNode;//这个结点的父结点
    6: .......
    

    1.1 读取所有的数据.

    使用的时候,首先声明一个XmlDocument对象,然后调用Load方法,从指定的路径加载XML文件.
    1: XmlDocument doc = new XmlDocument();
    2: doc.Load(@"..\..\Book.xml");
    


    然后可以通过调用SelectSingleNode得到指定的结点,通过GetAttribute得到具体的属性值.参看下面的代码

    // 得到根节点bookstore
    XmlNode xn = xmlDoc.SelectSingleNode("bookstore");
    
    
    // 得到根节点的所有子节点
    XmlNodeList xnl = xn.ChildNodes;
    
    foreach (XmlNode xn1 in xnl)
    {
       BookModel bookModel = new BookModel();
       // 将节点转换为元素,便于得到节点的属性值
       XmlElement xe = (XmlElement)xn1;
       // 得到Type和ISBN两个属性的属性值
       bookModel.BookISBN = xe.GetAttribute("ISBN").ToString();
       bookModel.BookType = xe.GetAttribute("Type").ToString();
       // 得到Book节点的所有子节点
       XmlNodeList xnl0 = xe.ChildNodes;
       bookModel.BookName=xnl0.Item(0).InnerText;
       bookModel.BookAuthor=xnl0.Item(1).InnerText;
       bookModel.BookPrice=Convert.ToDouble(xnl0.Item(2).InnerText);
       bookModeList.Add(bookModel);
     }
     dgvBookInfo.DataSource = bookModeList;
    

    在正常情况下,上面的代码好像没有什么问题,但是对于读取上面的XML文件,则会出错,原因就是因为我上面的XML文件里面有注释,大家可以参看Book.xml文件中的第三行,我随便加的一句注释.注释也是一种结点类型,在没有特别说明的情况下,会默认它也是一个结点(Node).所以在把结点转换成元素的时候就会报错.”无法将类型为“System.Xml.XmlComment”的对象强制转换为类型“System.Xml.XmlElement”。”

    Snap2_thumb1

    幸亏它里面自带了解决办法,那就是在读取的时候,告诉编译器让它忽略掉里面的注释信息.修改如下:

    1: XmlDocument xmlDoc = new XmlDocument();
    2: XmlReaderSettings settings = new XmlReaderSettings();
    3: settings.IgnoreComments = true;//忽略文档里面的注释
    4: XmlReader reader = XmlReader.Create(@"..\..\Book.xml", settings);
    5: xmlDoc.Load(reader);
    

    最后读取完毕后,记得要关掉reader.

       1: reader.Close();



    这样它就不会出现错误.

    最后运行结果如下:

    image_thumb8

    1.2 增加一本书的信息.

    1.2 增加一本书的信息.

    向文件中添加新的数据的时候,首先也是通过XmlDocument加载整个文档,然后通过调用SelectSingleNode方法获得根结点,通过CreateElement方法创建元素,用CreateAttribute创建属性,用AppendChild把当前结点挂接在其它结点上,用SetAttributeNode设置结点的属性.具体代码如下:

    加载文件并选出要结点:

    1: XmlDocument doc = new XmlDocument();
    2: doc.Load(@"..\..\Book.xml");
    3: XmlNode root = doc.SelectSingleNode("bookstore");
    

    创建一个结点,并设置结点的属性:

    1: XmlElement xelKey = doc.CreateElement("book");
    2: XmlAttribute xelType = doc.CreateAttribute("Type");
    3: xelType.InnerText = "adfdsf";
    4: xelKey.SetAttributeNode(xelType);
    

    创建子结点:

    1: XmlElement xelAuthor = doc.CreateElement("author");
    2: xelAuthor.InnerText = "dfdsa";
    3: xelKey.AppendChild(xelAuthor);
    

    最后把book结点挂接在要结点上,并保存整个文件:

    1: root.AppendChild(xelKey);
    2: doc.Save(@"..\..\Book.xml");
    

    用上面的方法,是向已有的文件上追加数据,如果想覆盖原有的所有数据,可以更改一下,使用LoadXml方法:

    1: XmlDocument doc = new XmlDocument();
    2: doc.LoadXml("<bookstore></bookstore>");//用这句话,会把以前的数据全部覆盖掉,只有你增加的数据
    

    直接把根结点选择出来了,后面不用SelectSingleNode方法选择根结点,直接创建结点即可,代码同上.

    1.3 删除某一个数据

    想要删除某一个结点,直接找到其父结点,然后调用RemoveChild方法即可,现在关键的问题是如何找到这个结点,上面的SelectSingleNode可以传入一个Xpath表,我们通过书的ISBN号来找到这本书所在的结点.如下:

       1: XmlElement xe = xmlDoc.DocumentElement; // DocumentElement 获取xml文档对象的根XmlElement.
       2: string strPath = string.Format("/bookstore/book[@ISBN=\"{0}\"]", dgvBookInfo.CurrentRow.Cells[1].Value.ToString());
       3: XmlElement selectXe = (XmlElement)xe.SelectSingleNode(strPath);  //selectSingleNode 根据XPath表达式,获得符合条件的第一个节点.
       4: selectXe.ParentNode.RemoveChild(selectXe);
    "/bookstore/book[@ISBN=\"{0}\"]"是一个Xpath表达式,找到ISBN号为所选那一行ISBN号的那本书,有关Xpath的知识请参考:XPath 语法
    

    1.4 修改某要条数据

    修改某 条数据的话,首先也是用Xpath表达式找到所需要修改的那一个结点,然后如果是元素的话,就直接对这个元素赋值,如果是属性的话,就用SetAttribute方法设置即可.如下:

    1: XmlElement xe = xmlDoc.DocumentElement; // DocumentElement 获取xml文档对象的根XmlElement.
    2: string strPath = string.Format("/bookstore/book[@ISBN=\"{0}\"]", dgvBookInfo.CurrentRow.Cells[1].Value.ToString());
    3: XmlElement selectXe = (XmlElement)xe.SelectSingleNode(strPath);  //selectSingleNode 根据XPath表达式,获得符合条件的第一个节点.
    4: selectXe.SetAttribute("Type", dgvBookInfo.CurrentRow.Cells[0].Value.ToString());//也可以通过SetAttribute来增加一个属性
    5: selectXe.GetElementsByTagName("title").Item(0).InnerText = dgvBookInfo.CurrentRow.Cells[2].Value.ToString();
    6: selectXe.GetElementsByTagName("author").Item(0).InnerText = dgvBookInfo.CurrentRow.Cells[3].Value.ToString();
    7: selectXe.GetElementsByTagName("price").Item(0).InnerText = dgvBookInfo.CurrentRow.Cells[4].Value.ToString();
    8: xmlDoc.Save(@"..\..\Book.xml");
    

    2.使用XmlTextReader和XmlTextWriter

    XmlTextReader和XmlTextWriter是以流的形式来读写XML文件.
    

    2.1XmlTextReader

    使用XmlTextReader读取数据的时候,首先创建一个流,然后用read()方法来不断的向下读,根据读取的结点的类型来进行相应的操作.如下:

     1: XmlTextReader reader = new XmlTextReader(@"..\..\Book.xml");
     2:            List<BookModel> modelList = new List<BookModel>();
     3:            BookModel model = new BookModel();
     4:            while (reader.Read())
     5:            {
     6:               
     7:                if (reader.NodeType == XmlNodeType.Element)
     8:                {
     9:                    if (reader.Name == "book")
    10:                    {
    11:                        model.BookType = reader.GetAttribute(0);
    12:                        model.BookISBN = reader.GetAttribute(1);
    13:                    }
    14:                    if (reader.Name == "title")
    15:                    {
    16:                        model.BookName=reader.ReadElementString().Trim();
    17:                    }
    18:                    if (reader.Name == "author")
    19:                    {
    20:                        model.BookAuthor = reader.ReadElementString().Trim();
    21:                    }
    22:                    if (reader.Name == "price")
    23:                    {
    24:                        model.BookPrice = Convert.ToDouble(reader.ReadElementString().Trim());
    25:                    }
    26:                }
    27:  
    28:                if (reader.NodeType == XmlNodeType.EndElement)
    29:                {
    30:                    modelList.Add(model);
    31:                    model = new BookModel();
    32:                }
    33:  
    34:                
    35:            }
    36:            modelList.RemoveAt(modelList.Count-1);
    37:            this.dgvBookInfo.DataSource = modelList;
    

    关键是读取属性的时候,你要先知道哪一个结点具有几个属性,然后通过GetAttribute方法来读取.读取属性还可以用另外一种方法,就是用MoveToAttribute方法.可参见下面的代码:

     1: if (reader.Name == "book")
     2:     {
     3:         for (int i = 0; i < reader.AttributeCount; i++)
     4:         {
     5:             reader.MoveToAttribute(i);
     6:             string str = "属性:" + reader.Name + "=" + reader.Value;
     7:         }
     8:         model.BookType = reader.GetAttribute(0);
     9:         model.BookISBN = reader.GetAttribute(1);
    10:     }
    

    效果如下:

    2.2XmlTextWriter

    XmlTextWriter写文件的时候,默认是覆盖以前的文件,如果此文件名不存在,它将创建此文件.首先设置一下,你要创建的XML文件格式,

       1: XmlTextWriter myXmlTextWriter = new XmlTextWriter(@"..\..\Book1.xml", null);
       2: //使用 Formatting 属性指定希望将 XML 设定为何种格式。 这样,子元素就可以通过使用 Indentation 和 IndentChar 属性来缩进。
       3: myXmlTextWriter.Formatting = Formatting.Indented;
    然后可以通过WriteStartElement和WriteElementString方法来创建元素,这两者的区别就是如果有子结点的元素,那么创建的时候就用WriteStartElement,然后去创建子元素,创建完毕后,要调用相应的WriteEndElement来告诉编译器,创建完毕,用WriteElementString来创建单个的元素,用WriteAttributeString来创建属性.如下:
    
       1: XmlTextWriter myXmlTextWriter = new XmlTextWriter(@"..\..\Book1.xml", null);
       2:            //使用 Formatting 属性指定希望将 XML 设定为何种格式。 这样,子元素就可以通过使用 Indentation 和 IndentChar 属性来缩进。
       3:            myXmlTextWriter.Formatting = Formatting.Indented;
       4:  
       5:            myXmlTextWriter.WriteStartDocument(false);
       6:            myXmlTextWriter.WriteStartElement("bookstore");
       7:  
       8:            myXmlTextWriter.WriteComment("记录书本的信息");
       9:            myXmlTextWriter.WriteStartElement("book");
      10:  
      11:            myXmlTextWriter.WriteAttributeString("Type", "选修课");
      12:            myXmlTextWriter.WriteAttributeString("ISBN", "111111111");
      13:  
      14:            myXmlTextWriter.WriteElementString("author","张三");
      15:            myXmlTextWriter.WriteElementString("title", "职业生涯规划");
      16:            myXmlTextWriter.WriteElementString("price", "16.00");
      17:  
      18:            myXmlTextWriter.WriteEndElement();
      19:            myXmlTextWriter.WriteEndElement();
      20:  
      21:            myXmlTextWriter.Flush();
      22:            myXmlTextWriter.Close();
    

    3.使用Linq to XML.

    Linq是C#3.0中出现的一个新特性,使用它可以方便的操作许多数据源,也包括XML文件.使用Linq操作XML文件非常的方便,而且也比较简单.下面直接看代码,

    先定义 一个方法显示查询出来的数据

     1: private void showInfoByElements(IEnumerable<XElement> elements)
     2:        {
     3:            List<BookModel> modelList = new List<BookModel>();
     4:            foreach (var ele in elements)
     5:            {
     6:                BookModel model = new BookModel();
     7:                model.BookAuthor = ele.Element("author").Value;
     8:                model.BookName = ele.Element("title").Value;
     9:                model.BookPrice = Convert.ToDouble(ele.Element("price").Value);
    10:                model.BookISBN=ele.Attribute("ISBN").Value;
    11:                model.BookType=ele.Attribute("Type").Value;
    12:                
    13:                modelList.Add(model);
    14:            }
    15:            dgvBookInfo.DataSource = modelList;
    16:        }
    

    3.1读取所有的数据

    直接找到元素为book的这个结点,然后遍历读取所有的结果.

    1: private void btnReadAll_Click(object sender, EventArgs e)
    2: {
    3: XElement xe = XElement.Load(@”....\Book.xml”);
    4: IEnumerable elements = from ele in xe.Elements(“book”)
    5: select ele;
    6: showInfoByElements(elements);
    7: }
    3.2插入一条数据

    插入结点和属性都采用new的方法,如下:
    1: private void btnInsert_Click(object sender, EventArgs e)
    2: {
    3: XElement xe = XElement.Load(@”....\Book.xml”);
    4: XElement record = new XElement(
    5: new XElement(“book”,
    6: new XAttribute(“Type”, “选修课”),
    7: new XAttribute(“ISBN”,”7-111-19149-1”),
    8: new XElement(“title”, “计算机操作系统”),
    9: new XElement(“author”, “7-111-19149-1”),
    10: new XElement(“price”, 28.00)));
    11: xe.Add(record);
    12: xe.Save(@”....\Book.xml”);
    13: MessageBox.Show(“插入成功!”);
    14: btnReadAll_Click(sender, e);
    15: }
    3.3 删除选中的数据

    首先得到选中的那一行,通过ISBN号来找到这个元素,然后用Remove方法直接删除,如下:

    1: private void btnDelete_Click(object sender, EventArgs e)
    2: {
    3: if (dgvBookInfo.CurrentRow != null)
    4: {
    5: //dgvBookInfo.CurrentRow.Cells[1]对应着ISBN号
    6: string id = dgvBookInfo.CurrentRow.Cells[1].Value.ToString();
    7: XElement xe = XElement.Load(@”....\Book.xml”);
    8: IEnumerable elements = from ele in xe.Elements(“book”)
    9: where (string)ele.Attribute(“ISBN”) == id
    10: select ele;
    12: {
    11: if (elements.Count() > 0)
    13: elements.First().Remove();
    14: }
    15: xe.Save(@”....\Book.xml”);
    16: MessageBox.Show(“删除成功!”);
    17: btnReadAll_Click(sender, e);
    18:
    19: }
    20: }
    3.4 删除所有的数据

    与上面的类似,选出所有的数据,然后用Remove方法,如下:

    1: private void btnDeleteAll_Click(object sender, EventArgs e)
    2: {
    3: XElement xe = XElement.Load(@”....\Book.xml”);
    4: IEnumerable elements = from ele in xe.Elements(“book”)
    5: select ele;
    6: if (elements.Count() > 0)
    7: {
    8: elements.Remove();
    9: }
    10: xe.Save(@”....\Book.xml”);
    11: MessageBox.Show(“删除成功!”);
    12: btnReadAll_Click(sender, e);
    13: }
    3.5 修改某一记录

    首先得到所要修改的某一个结点,然后用SetAttributeValue来修改属性,用ReplaceNodes来修改结点元素。如下:

    1: private void btnSave_Click(object sender, EventArgs e)
    2: {
    3: XElement xe = XElement.Load(@”....\Book.xml”);
    4: if (dgvBookInfo.CurrentRow != null)
    5: {
    6: //dgvBookInfo.CurrentRow.Cells[1]对应着ISBN号
    7: string id = dgvBookInfo.CurrentRow.Cells[1].Value.ToString();
    8: IEnumerable element = from ele in xe.Elements(“book”)
    9: where ele.Attribute(“ISBN”).Value == id
    10: select ele;
    11: if (element.Count() > 0)
    12: {
    13: XElement first = element.First();
    14: ///设置新的属性
    15: first.SetAttributeValue(“Type”, dgvBookInfo.CurrentRow.Cells[0].Value.ToString());
    16: ///替换新的节点
    17: first.ReplaceNodes(
    18: new XElement(“title”, dgvBookInfo.CurrentRow.Cells[2].Value.ToString()),
    19: new XElement(“author”, dgvBookInfo.CurrentRow.Cells[3].Value.ToString()),
    20: new XElement(“price”, (double)dgvBookInfo.CurrentRow.Cells[4].Value)
    21: );
    22: }
    23: xe.Save(@”....\Book.xml”);
    24:
    25: MessageBox.Show(“修改成功!”);
    26: btnReadAll_Click(sender, e);
    27: }
    28: }

    最终效果如下:

    image_thumb15

    有关Linq to XML的知识大家可以参考LINQ国人首创LINQ专著——《精通LINQ数据访问技术》

    这次就写到这了,我个人也在学习,所以如果大家发现错误,敬请批评指正,共同学习。

    源码

    如何搭建微软聊天机器人Microsoft bot Framework ---get start

    暑假时团队做了一个个Gitlab统计网站,并且与slack通过bot进行关联,此篇博文不讲网站,就讲一下bot入门—实现能够在本地进行交互的聊天机器人

    microsoft bot framework的使用

    1. 在本地的vs要选择Visual Studio 2015 (latest update),可以点击此处下载免费社区版。
    2. 下载安装bot application template,然后不用解压,直接将压缩包直接放到 “%USERPROFILE%\Documents\Visual Studio 2015\Templates\ProjectTemplates\Visual C#\”这个路径下面。USERPROFILE指的是当前电脑用户,比如C:\Users\用户名.
    3. 打开vs,就能看到Bot Application
      QQ截图20160719105900

    默认目录中,你会在 Controllers\MessagesController.cs中看到一下代码

    [BotAuthentication]
    public class MessagesController : ApiController
    {
    ///
    /// POST: api/Messages
    /// Receive a message from a user and reply to it
    ///
    public async Task Post([FromBody]Activity activity)
    {
    if (activity.Type == ActivityTypes.Message)
    {
    ConnectorClient connector = new ConnectorClient(new Uri(activity.ServiceUrl));
    // calculate something for us to return
    int length = (activity.Text ?? string.Empty).Length;
    // return our reply to the user
    Activity reply = activity.CreateReply($“You sent {activity.Text} which was {length} characters”);
    await connector.Conversations.ReplyToActivityAsync(reply);
    }
    else
    {
    HandleSystemMessage(activity);
    }
    var response = Request.CreateResponse(HttpStatusCode.OK);
    return response;
    }
    

    这是最重要的一个方法。

    直接建立的模板是直接可以运行的,但是在运行之前,需要建立下载微软的bot模拟器,安装此模拟器。

    启动项目,会在浏览器中看到,注意记住端口号,在模拟器中将会用到,这里用的是3979

    QQ截图20160719110957

    打开模拟器QQ截图20160719112912

    可以看到,有三处地方,bot url,app id,app password,因为是在本地模拟,那么app id,app password可以暂时不用填写,将bot url中端口号与浏览器中对应,其他的不用管(user指的是用户名,比如发送:“我的手机号码是什么?”,bot会将“我”自动识别为我的bot项目中的用户名)QQ截图20160719114530

    看到这个说明运行环境没有问题,至于想要bot帮你作什么事情,需要自己实现后台逻辑代码。

     

    接下来几篇文章会讲一下如何应用

    sql server 存储过程入门(一)以及C#简单调用

        Transact-SQL中的存储过程,非常类似于编程语言中的方法,它可以重复调用。当存储过程执行一次后,可以将语句缓存中,这样下次执行的时候直接使用缓存中的语句。这样就可以提高存储过程的性能。

    基本概念

        存储过程是由SQL 语句和控制流程语句构成的语句块(语句集合)。他不仅可以输入参数,还可以输出参数。存储过程可以通过接收参数向调用者返回结果集,结果集的格式由调用者确定。可以在存储过程中调用另一个存储过程

    创建存储过程并SSMS中执行

    使用 SQL Server Management Studio

    1. 在 “对象资源管理器”中,连接到 数据库引擎 的实例,然后展开该实例。
    2. 依次展开 “数据库”、 AdventureWorks2012 数据库和 “可编程性”。
    3. 右键单击“存储过程”,再单击“新建存储过程”。
    4. 在 “查询” 菜单上,单击 “指定模板参数的值”。
    5. 在 “指定模板参数的值” 对话框中,输入下列所示的参数值。
    参数
    author 作者
    Create date 创建日期
    Descript 介绍
    Procedure_name GetXHG
    @Param1 @UserName
    @Datatype_For_Param1 nchar(100)
    Default_Value_For_Param1 NULL
    @Param2
    @Datatype_For_Param2
    Default_Value_For_Param2
    1. 点击“确定”
    2. 查询编辑器中,试用一下语句代替SELECT 语句

      SELECT password,email,sex,RANK,groupname,isdelete,buildtime  
      from Member  
      where UserName = @username
      
    1. 若要测试语法,请在 “查询” 菜单上,单击 “分析”。 如果返回错误消息,则请将这些语句与上述信息进行比较,并视需要进行更正。
    2. 若要创建该过程,请在 “查询” 菜单上单击 “执行”。 该过程作为数据库中的对象创建。
    3. 若要查看在对象资源管理器中列出的过程,请右键单击“存储过程”,然后选择“刷新”。
    4. 若要运行该过程,请在对象资源管理器中右键单击存储过程名称 GetXHG,然后选择“执行存储过程”。
    5. 在“执行过程”窗口中,输入 xiehongguang 作为参数 @UserName 的值。
          

    使用 Transact-SQL 在查询编辑器中创建过程

    1. 在 “对象资源管理器”中,连接到 数据库引擎的实例。
    2. 从 “文件” 菜单中,单击 “新建查询”。
    3. 将以下示例复制并粘贴到查询窗口中,然后单击 “执行”。 该示例将使用其他过程名称创建与上述相同的存储过程。

      USE LuckyGitlabStats;  
      GO  
      CREATE PROCEDURE GetXHG   
          @UserName nchar(100)  
      AS   
          SELECT password,email,sex,RANK,groupname,isdelete,buildtime  
          from Member  
          where UserName = @username;  
      GO  
      
    4. 若要运行该过程,请将以下示例复制并粘贴到一个新的查询窗口中,然后单击 “执行”。 请注意,将显示指定参数值的不同方法。

      [USE Lucky;]  
      [GO]
      
      EXECUTE GetXHG N'xiehongguang';  
      -- Or  
      EXEC dbo.GetXHG @username = N'xiehongguang';  
      GO  
      -- Or  
      EXECUTE GetXHG @username = N'xiehongguang';  
      GO 
      

    C# 调用执行

    public List<Member> gettest()
    {
        List<Member> members = new List<Member>();
        ConnectLocalSQL connectLocaldb = new ConnectLocalSQL();
        SqlConnection conn = connectLocaldb.ConnectDataBase();
        //打开数据库
        conn.Open();
        //创建查询语句
        SqlCommand querySingleInfo = conn.CreateCommand();
        querySingleInfo.CommandText = "GetXHG";
        querySingleInfo.CommandType = System.Data.CommandType.StoredProcedure;
    
        //querySingleInfo.Parameters.Add("@username", SqlDbType.NChar);
        //querySingleInfo.Parameters["@username"].Value = "xiehongguang";
    
        querySingleInfo.Parameters.AddWithValue("@username", "xiehongguang");
        SqlDataReader userInfoReader = querySingleInfo.ExecuteReader();
        //有多行数据,用while循环
        while (userInfoReader.Read())
        {
            Member member = new Member();
          // member.username = userInfoReader["UserName"].ToString().Trim();
            member.password = userInfoReader["Password"].ToString().Trim();
            member.email = userInfoReader["Email"].ToString().Trim();
            member.sex = userInfoReader["Sex"].ToString().Trim();
            member.rank = userInfoReader["Rank"].ToString().Trim();
            member.groupName = userInfoReader["Groupname"].ToString().Trim();
            member.isdelete = userInfoReader["IsDelete"].ToString().Trim();
            members.Add(member);
        }
        //关闭查询
        userInfoReader.Close();
        //关闭数据库连接
        conn.Close();
        return members;
    } 
    

    参考

    https://docs.microsoft.com/zh-cn/sql/relational-databases/stored-procedures/create-a-stored-procedure
    https://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlcommand(v=vs.110).aspx
    《SQL 查询的艺术》

    |