1. 程式人生 > >Revit二次開發高階應用(1)——利用wcf做簡單的族庫管理

Revit二次開發高階應用(1)——利用wcf做簡單的族庫管理

因為對應用場景不是特別明確,暫時就用wcf做一個可以上傳和下載的功能來管理族庫。

1、用WCF做服務端的上傳下載管理

首先新增上傳下載的介面:

[ServiceContract]
    public interface IFileService
    {
        //上傳檔案
        [OperationContract]
        UpFileResult UpLoadFile(UpFile filestream);

        //下載檔案
        [OperationContract]
        DownFileResult DownLoadFile(DownFile downfile);
    }

    [MessageContract]
    public class DownFile
    {
        [MessageHeader]
        public string FileName { get; set; }
    }

    [MessageContract]
    public class UpFileResult
    {
        [MessageHeader]
        public bool IsSuccess { get; set; }
        [MessageHeader]
        public string Message { get; set; }
    }

    [MessageContract]
    public class UpFile
    {
        [MessageHeader]
        public long FileSize { get; set; }
        [MessageHeader]
        public string FileName { get; set; }
        [MessageBodyMember]
        public Stream FileStream { get; set; }
    }

    [MessageContract]
    public class DownFileResult
    {
        [MessageHeader]
        public long FileSize { get; set; }
        [MessageHeader]
        public bool IsSuccess { get; set; }
        [MessageHeader]
        public string Message { get; set; }
        [MessageBodyMember]
        public Stream FileStream { get; set; }
    }

然後實現介面:

public class FileService : IFileService
    {
        public UpFileResult UpLoadFile(UpFile filedata)
        {
            UpFileResult result = new UpFileResult();

            string path = System.AppDomain.CurrentDomain.BaseDirectory + @"\service\";

            if (!Directory.Exists(path))
            {
                Directory.CreateDirectory(path);
            }

            byte[] buffer = new byte[filedata.FileSize];

            FileStream fs = new FileStream(path + filedata.FileName, FileMode.Create, FileAccess.Write);

            int count = 0;
            while ((count = filedata.FileStream.Read(buffer, 0, buffer.Length)) > 0)
            {
                fs.Write(buffer, 0, count);
            }
            //清空緩衝區
            fs.Flush();
            //關閉流
            fs.Close();

            result.IsSuccess = true;

            return result;

        }

        //下載檔案
        public DownFileResult DownLoadFile(DownFile filedata)
        {

            DownFileResult result = new DownFileResult();

            string path = System.AppDomain.CurrentDomain.BaseDirectory + @"\service\" + filedata.FileName;

            if (!File.Exists(path))
            {
                result.IsSuccess = false;
                result.FileSize = 0;
                result.Message = "伺服器不存在此檔案";
                result.FileStream = new MemoryStream();
                return result;
            }
            Stream ms = new MemoryStream();
            FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read);
            fs.CopyTo(ms);
            ms.Position = 0;  //重要,不為0的話,客戶端讀取有問題
            result.IsSuccess = true;
            result.FileSize = ms.Length;
            result.FileStream = ms;

            fs.Flush();
            fs.Close();
            return result;
        }
    }

開啟服務:

 static void Main(string[] args)
        {
            ServiceHost host = new ServiceHost(typeof(FileService));
            host.Open();
            Console.WriteLine("開啟服務");
            Console.ReadKey();
        }

配置net.tcp繫結,NetTcpBinding用於跨機器互動表現的效果較好,所以這裡用這個繫結。對應的環境設定:

<system.serviceModel>
        <behaviors>
            <serviceBehaviors>
                <behavior name="">
                    <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
                    <serviceDebug includeExceptionDetailInFaults="false" />
                </behavior>
            </serviceBehaviors>
        </behaviors>
      <bindings>
        <netTcpBinding>
          <binding name="MyTcpBinding" maxBufferSize="2147483647" maxReceivedMessageSize="2147483647" sendTimeout="00:30:00" transferMode="Streamed"   >
            <security mode="None"></security>
          </binding>
        </netTcpBinding>
      </bindings>
      <services>
            <service name="ServiceTest.FileService">
                <endpoint address="net.tcp://localhost/mysever" binding="netTcpBinding" contract="ServiceTest.IFileService" bindingConfiguration="MyTcpBinding">
                    <identity>
                        <dns value="localhost" />
                    </identity>
                </endpoint>
                <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
                <host>
                    <baseAddresses>
                        <add baseAddress="http://localhost:8733/Design_Time_Addresses/ServiceTest/Service1/" />
                    </baseAddresses>
                </host>
            </service>
        </services>
    </system.serviceModel>

2.客戶端實現上傳下載

這其中有個重要的一點是,客戶端不能用App.config來配置服務環境,所以這裡需要用程式碼來實現配置,這點非常重要,不然會報錯,實現不了。根據服務端來實現客戶端的繫結配置:

Uri baseUri = new Uri("net.tcp://localhost/mysever");
            EndpointAddress epaddr = new EndpointAddress(baseUri);
            NetTcpBinding binding = new NetTcpBinding();
            binding.Name = "MyTcpBinding";
            binding.MaxBufferSize = 2147483647;
            binding.MaxReceivedMessageSize = 2147483647;
            binding.SendTimeout = new TimeSpan(0,30,0);
            binding.TransferMode = TransferMode.Streamed;
            binding.Security.Mode = SecurityMode.None;

然後客戶端還需要寫介面,這個跟服務端一樣即可。

wpf頁面的後臺完整程式碼:

IFileService m_instance;
        public UpDateFileView()
        {
            InitializeComponent();
            Uri baseUri = new Uri("net.tcp://localhost/mysever");
            EndpointAddress epaddr = new EndpointAddress(baseUri);
            NetTcpBinding binding = new NetTcpBinding();
            binding.Name = "MyTcpBinding";
            binding.MaxBufferSize = 2147483647;
            binding.MaxReceivedMessageSize = 2147483647;
            binding.SendTimeout = new TimeSpan(0,30,0);
            binding.TransferMode = TransferMode.Streamed;
            binding.Security.Mode = SecurityMode.None;
            m_instance = ChannelFactory<IFileService>.CreateChannel(binding, epaddr);
        }
        private void updataFile_Click(object sender, RoutedEventArgs e)
        {
            OpenFileDialog Fdialog = new OpenFileDialog();

            if (Fdialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {

                using (Stream fs = new FileStream(Fdialog.FileName, FileMode.Open, FileAccess.Read))
                {
                    this.filepath.Text = Fdialog.SafeFileName;
                    UpFileResult result = m_instance.UpLoadFile(new UpFile() {FileName= Fdialog.SafeFileName,FileSize= fs.Length,FileStream= fs});

                    if (result.IsSuccess == true)
                    {
                        System.Windows.MessageBox.Show("上傳成功!");
                    }
                    else
                    {
                        System.Windows.MessageBox.Show("上傳失敗!");
                    }
                }
            }
        }

        private void downloadFile_Click(object sender, RoutedEventArgs e)
        {
            string filename = this.filename.Text;
            string path = System.AppDomain.CurrentDomain.BaseDirectory + @"\client\";
            Stream filestream = new MemoryStream();
            //long filesize = m_instance.DownLoadFile(filename, out issuccess, out message, out filestream);
            DownFileResult filesize = m_instance.DownLoadFile(new DownFile() { FileName = filename });
            if (filesize.IsSuccess)
            {
                if (!Directory.Exists(path))
                {
                    Directory.CreateDirectory(path);
                }

                byte[] buffer = new byte[filesize.FileSize];
                FileStream fs = new FileStream(path + filename, FileMode.Create, FileAccess.Write);
                int count = 0;
                while ((count = filestream.Read(buffer, 0, buffer.Length)) > 0)
                {
                    fs.Write(buffer, 0, count);
                }

                //清空緩衝區
                fs.Flush();
                //關閉流
                fs.Close();
                System.Windows.MessageBox.Show("下載成功!");

            }
            else
            {

                System.Windows.MessageBox.Show("下載失敗!");

            }
        }

這樣就實現了客戶端的截面邏輯。

最後實現一下 IExternalCommand介面即可。

namespace Revit
{
    [Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)]
    [Autodesk.Revit.Attributes.Journaling(Autodesk.Revit.Attributes.JournalingMode.NoCommandData)]
    public class Class1 : IExternalCommand
    {
        public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
        {
            UpDateFileView view = new UpDateFileView();
            view.ShowDialog();
            return Result.Succeeded;
        }
    }
}

當然還有許多工作要做,比如上傳路徑,限定上傳檔案的字尾名,上傳的族檔案的管理,使用者名稱及密碼的驗證等等,這些細節處理好後,就可以實現族庫管理的功能。