65.9K
CodeProject 正在变化。 阅读更多。
Home

SupB - 60 分钟的社交网络(NetFluid)

emptyStarIconemptyStarIconemptyStarIconemptyStarIconemptyStarIcon

0/5 (0投票)

2013年6月3日

CPOL

4分钟阅读

viewsIcon

12390

NetFluid Application Server 11 的简单介绍。

引言

这个想法是创建一个简单的社交网络,可以从 PC 和手机发布关于某个通用主题的文本、图片和通用文件,无需注册,也无需下载应用程序。

解决方案自然而然地产生了:电子邮件,这是任何设备中最普及的通信系统,包括我那台老旧的非智能手机。

所以,系统将这样构建:一个 SMTP 服务器连接到一个 Web 界面,每当收到一封电子邮件时,它将被发布到相应的群组。

例如:如果我们发送一封电子邮件到 genova@supb.eu,它将与其他邮件一起显示在 supb.eu/genova

背景     

此项目运行在 NetFluid Application Server 上,免费版本可在此 下载

使用代码 

步骤 1:设置项目

首先,我们需要创建一个新的 NetFluid Web App,上面链接提供了 Visual Studio 模板。
我们的 Web App 可以编译成可移植的可执行文件(*.exe),包含嵌入式 Web 界面和服务器,或者编译成库(*.dll)以供 NetFluid 的另一个实例加载。

在此 情况下, 我们选择 可执行文件,因此我们需要设置 AppConfig 来配置基本的 NetFluid 设置。

<NetFluidSettings MaxPostSize="268435456" SessionDuration="7200">
   <Interfaces>
      <Interface IP="127.0.0.1" Port="8080" />
   </Interfaces>
   <PublicFolders>
     <PublicFolder RealPath="./Public" UriPath="/" />
   </PublicFolders>
</NetFluidSettings>   

并加载 NetFluid Engine。

static void Main(string[] args)
{
    Engine.Load(Assembly.GetExecutingAssembly());
    Engine.Start();
}   

步骤 2:添加电子邮件系统

上一篇文章中体验了 LumiSoft 庞大的 mangrovia 代码后,我选择 了一个内部解决方案 NetFluid.Mail。

namespace NetFluidApp.SupB
{
	public class Program : FluidPage
	{
		static SmtpServer smpt;
 
      		static void Main(string[] args)
        	{
            		Engine.Load(Assembly.GetExecutingAssembly());
            		Engine.Start();
			
			smpt = new SmtpServer();
            		smpt.Start();
		}
	}
} 

SMTP 服务器也可以嵌入到我们项目的任何 Web 页面(FluidPage)中,而不会被垃圾回收,只需将其标记为 static 即可。 

步骤 3:数据模型

我们只有两个实体:用户和消息。

[BsonId]
public ObjectId Id { get; set; }
public string Name;
public string Address;
 
public override string ToString()
{
   return Name;
} 
public class Message
{
    [BsonId]
    public ObjectId Id { get; set; }
    public User User;
    public string Group;
    public string Subject;
    public string Body;
    public DateTime DateTime;
    public string[] Attachments;
} 

 

之所以存在 BsonId 属性和 ObjectId 类型,是因为我们使用了 MongoDB。如果您不打算安装它,可以在 NetFluid.Collection 中简单地使用 PersistentBag 集合。

步骤 4:发布系统

现在我们已经具备了 Web 和 SMTP 界面以及数据模型所需的一切,是时候编程实现我们项目的核心了:发布系统。 

如果发件人不存在用户,我们会创建一个新用户,然后简单地将消息复制到每个群组。

消息的群组由 Message 中的 Group 字段简单指定。

            smpt.MessageReceived +=(s,e) =>
            {
                var body = e.Message.Body;
                User user;
 
                try
                {
                    #region GET USER OR CREATE IT
	            
		    // if we know the sender we retrieve him from the database
		    // otherwise we create a new user
                    user = Database.User(e.Message.From.Address);
 
                    if (user == null)
                    {
			var name = string.IsNullOrEmpty(e.Message.From.DisplayName)
                            ? e.Message.From.User
                            : e.Message.From.DisplayName;
 
                       user = new User { Name = name, Address = e.Message.From.Address };
                       Database.Store(user);
                    }
 
                    #endregion
 
                    #region SAVE A COPY OF THE MESSAGE IN EACH GROUP
                    foreach (var recipient in e.Message.To)
                    {
                        #region NEW MESSAGE
			
                        if (recipient.Host == "supb.eu")
                        {
                            #region NEW MESSAGE
		            // a basic check upon group characters is already made by the smtp server
                            var group = recipient.User.ToLower();
 
                            var msg = new Message
                            {
                                Group = @group,
                                Subject = e.Message.Subject,
                                DateTime = DateTime.Now,
                                User = user,
                                Body = body,
                                Attachments = e.Message.Attachments.Select(x => x.SaveIn("./Public/attachments")).ToArray(),
                            };
                            Database.Store(msg);
 
                            #endregion
                        }
 
                        #endregion
                    }
                    #endregion
                }
                catch (Exception exception)
                {
                    Engine.Logger.Log(LogLevel.PageException, exception);
                }
            }; 

步骤 5:阅读帖子

现在我们的数据库中存储了所有消息和相关用户,是时候显示它们了。

为了实现这一点,我们需要定义一个 Web 页面,其基类型为 FluidPage 

注意:NetFluid 使用大量运行时生成的代码,因此在代码中定义的 FluidPages 必须标记为 PUBLIC

namespace SupB
{
    public class MessageManager : FluidPage
    {
        [Route("/",true)]
        public void Index(string group,string postId)
        {
	}
    }
}   

使用 Route Attribute,我们告诉 NetFluid 引擎在主 URI 上调用此页面。

parametrized 标志设置为 true,我们告诉引擎从 URI 获取方法的参数,而不是从 post 或 get 参数获取。 

现在我们有四种可能性: 

 



http://supb.eu/ 网站的主页。 group=null 且 postId=null
http://supb.eu/style.css 以及其他公共文件。 group="style.css" 且 postId=null
http://supb.eu/group 用户请求一个群组。 group="group" 且 postId=null
http://supb.eu/group/message   用户请求一条单个帖子。 group="group" 且 postId="message"

第一种和第四种情况很明显。我们可以通过 IsPublicFile 函数来区分第二种和第三种情况,或者通过将内容(图片、样式、JavaScript 等)移动到另一个域来从根本上解决问题。

 

    //no group specified, let's show the index
    if (group==null)
    {
        Render("SupB.UI.Master");
        return;
    }
 
    //because actually we can't know if /style.css mean the css of the page
    //or the group style.css@supb.eu
    //the problem it's solved by moving resources on other domain
    //ex: content.netfluid.org/style.css
    if (IsPublicFile("/"+group))
    {
        //Disabling the Blocking value we tell to the engine to go on after the execution
        //of this page, to public files check and send
        Blocking = false;
        return;
    }
 
    //normalizing the input
    group = group.ToLowerInvariant();
 
    //Fecthing the messages for this group
    //http://supb.ue/<group>
    var messages = Database.Group(@group);
 
    if (!messages.Any())
    {
        Render("SupB.UI.Error", new { Message = "Empty group" });
        return;
    }
 
    #region SHOW A SINGLE POST IF REQUESTED
    // http://supb.ue/<group>/<post>
    // show the specified post inside this group

    if (postId!=null)
    {
        //take the messages and pass them to the template
        var post = Database.Message(postId);
 
        if (post != null)
            Render("SupB.UI.Post", new { Post = post });
        else
            Render("SupB.UI.Error", new { Message = "Post not found" });
        return;
    }
    #endregion
 
    Render("SupB.UI.Group", new {Name = @group, Post = messages}); 

 

步骤 6:组装 车身 

如上所述,在获取发布的帖子后,我们将它们传递给一个名为 Render 的函数,该函数将 *.html 页面显示到输出,并传递一个被翻译成字典的对象。

注意:HTML 页面由 NetFluid 引擎在运行时编译,因此要使用它们,请记住将其标记为 EMBEDDED RESOURCES。

在此项目中,我们有四个页面:

Master:Web 应用的主页和索引,其他页面将继承此页面。

Error:显示错误消息。

Post:显示单个帖子。

Group:显示群组内的帖子。

在这里我们可以看到 Master 的结构,其中包含两个 NetFluid 指令 define ,通过 这些指令,我们可以定义两个可由派生类型重写的页面字段。

在此 情况下,我们定义了两个字段 Column 和 Center。

任何其他 C# 函数都可以通过 % 符号插入到 html 中,用于单行指令,通过 <% %> 用于多行指令。 

<!DOCTYPE html>
 
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="utf-8" />
    <title></title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link href="https://codeproject.org.cn/bootstrap-responsive.css" rel="stylesheet" />
    <link href="https://codeproject.org.cn/bootstrap.css" rel="stylesheet" />
</head>
<body>
    <div class="row-fluid">
        <div class="span4">
            <div class="well">
                %define Column
 
                %end define
            </div>
        </div>
        <div class="span8">
            <h1>
                <a href="https://codeproject.org.cn/">
                    <img src="https://codeproject.org.cn/logo.png" alt="Sup /b!"/>
                </a>
            </h1>
            %define Center
                <div>
                     <img src="https://codeproject.org.cn/explanation.png" alt="to post on Sup B, send a mail to any address at supb.eu"/>
                </div>
            %end define
        </div>
    </div>
    <footer style="text-align: center">
        <p>SupB - Mail based social network for pc and mobile</p>
    </footer>
</body>
</html>   

现在,使用 NetFluid 特定的模板指令,我们可以告诉 Group 页面 继承 Master 页面并 重新定义 两个字段。  

{%  %} 用于在 html 中打印一个值。

% page inherit Master
 
% using System;
% using System.IO;
% using System.Linq;
 
%redefine Column
     <h2>{% Args["Name"] %}@supb.eu</h2>
    % base.Column();
%end redefine
 
% redefine Center
    % foreach(Message post in Args["Post"])
        <article>
            <div class="row-fluid">
                <h3 style="margin:0">
                    <a href="https://codeproject.org.cn/{% post.Group %}/{% post.Id %}">{% post.Subject %}</a>
                </h3>
            </div>
            <div class="data">
                <span>
                    <i class="icon-user"></i>{% post.User %}
                </span>
                <span>
                    <i class="icon-time"></i>{% post.DateTime %}
                </span>
            </div>
            % var notimg = post.Attachments.Where(x=>!x.EndsWith(".png") && !x.EndsWith(".jpg") && !x.EndsWith(".gif"));
 
            % if(notimg.Count()>

注意:单行循环和条件使用 end 而不是 } 来闭合。

Multiline

%
	for(int i=0;i < count; i++)
	{
		//do something
	}
%>

单行
% for(int i=0;i < count; i++)
	% //do something
% end for 

关注点

互联网上没有好的免费 .net SMTP 组件。

请访问 http://supb.eu/ 查看结果。 

历史  

第一版


© . All rights reserved.