所以目前的情况是我有一个完全利用MEF的程序。现在我想让它利用Rx,允许它扩展到更大的查询,并允许用户在各种插件返回结果时查看结果。它目前设置如下:
工作流程:查询=> DetermineTypes => QueryPlugins =>结果
目前,如果有人需要引用的内容超过我在下面发布的内容,则代码全部存储在GitHub上。 ALeRT on GitHub
在@Enigmativity的帮助下,主要部分是now running with Rx.现在,当我完成后,我认为我已经使用System.IObservable<string>
来设置框架来处理var.ToObservable()
。遗憾的是,这似乎不起作用(至少不像我有的那样)。插件框架目前设置如下:
public interface IQueryPlugin
{
string PluginCategory { get; }
string Name { get; }
string Version { get; }
string Author { get; }
System.Collections.Generic.List<string> TypesAccepted { get; }
System.IObservable<string> Result(string input, string type, bool sensitive);
}
我尝试修复的一个示例插件Result方法,但看起来失败了:
public System.IObservable<string> Result(string input, string type, bool sensitive)
{
string csv = "\"Roundtrip Time\"," + "\"Status\"\n";
if (sensitive == true)
{
csv += "\"" + "" + "\"," + "\"" + "FORBIDDEN" + "\"\n";
}
else
{
if (type == "URL")
{
input = new Uri(input).Host;
}
Ping ping = new Ping();
PingReply pingReply = ping.Send(input);
csv += "\"" + pingReply.RoundtripTime.ToString() + "\"," + "\"" + pingReply.Status.ToString() + "\"\n";
}
return csv.ToObservable();
}
这自然会出现以下错误:无法将System.IObservable<char>
隐式转换为System.IObservable<string>
。
所以问题是将数据从插件传递到主程序的最佳方法是什么。如果它有利于这种情况并且保持插件界面相对简单,我可以处理切换类型。目标是为任何自己编写的用户保持插件尽可能简单。
对于完成点,我将删除下面的整个MainWindow.xaml.cs以查看它当前是如何设置的。
using ALeRT.PluginFramework;
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using GenericParsing;
using System.Windows.Markup;
using System.Data;
using System.Reactive.Linq;
namespace ALeRT.UI
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var catalog = new AggregateCatalog();
catalog.Catalogs.Add(new DirectoryCatalog(Directory.GetCurrentDirectory()));
var container = new CompositionContainer(catalog);
try
{
container.ComposeParts(this);
}
catch (CompositionException compositionException)
{
MessageBox.Show(compositionException.ToString());
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
private void queryButton_Click(object sender, RoutedEventArgs e)
{
string line;
//resultDS.Reset(); //Looking for a way to clear our the contents from last time without breaking SelectionChanged
if (File.Exists(queryTB.Text) && (bool)listCB.IsChecked)
{
StreamReader file = null;
try
{
file = new StreamReader(queryTB.Text);
while ((line = file.ReadLine()) != null)
{
QueryPlugins(line, DetermineTypes(line), (bool)sensitiveCB.IsChecked);
}
}
finally
{
if (file != null) { file.Close(); }
}
}
else
{
QueryPlugins(queryTB.Text, DetermineTypes(queryTB.Text), (bool)sensitiveCB.IsChecked);
}
}
DataSet resultsDS = new DataSet("Results");
[ImportMany]
public IEnumerable<ITypePlugin> TPlugins { get; set; }
[ImportMany]
public IEnumerable<IQueryPlugin> QPlugins { get; set; }
/// <summary>
/// Method to process all Type plugins.
/// </summary>
private List<string> DetermineTypes(string val)
{
List<string> typeResultAL = new List<string>();
foreach (var tPlugins in this.TPlugins)
{
if (tPlugins.Result(val))
{
typeResultAL.Add(tPlugins.Name);
}
}
return typeResultAL;
}
/// <summary>
/// Method to process all Query plugins.
/// </summary>
private void QueryPlugins(string query, List<string> types, bool sensitive)
{
foreach (string tType in types) //Cycle through a List<string>
{
foreach (var qPlugins in this.QPlugins) //Cycle through all query plugins
{
foreach (string qType in qPlugins.TypesAccepted) //Cycle though a List<string> within the IQueryPlugin interface AcceptedTypes
{
if (qType == tType) //Match the two List<strings>, one is the AcceptedTypes and the other is the one returned from ITypeQuery
{
IObservable<DataTable> q =
from text in qPlugins.Result(query, qType, sensitive)
from tempTable in Observable.Using(
() => new GenericParserAdapter(),
parser => Observable.Using(() => new StringReader(text),
sr => Observable.Start<DataTable>(
() =>
{
var rNum = new Random();
parser.SetDataSource(sr);
parser.ColumnDelimiter = Convert.ToChar(",");
parser.FirstRowHasHeader = true;
parser.MaxBufferSize = 4096;
parser.MaxRows = 500;
parser.TextQualifier = '\"';
var tempTable = parser.GetDataTable();
tempTable.TableName = qPlugins.Name.ToString();
if (!tempTable.Columns.Contains("Query"))
{
DataColumn tColumn = new DataColumn("Query");
tempTable.Columns.Add(tColumn);
tColumn.SetOrdinal(0);
}
foreach (DataRow dr in tempTable.Rows)
dr["Query"] = query;
return tempTable;
}
)))
select tempTable;
}
}
}
}
}
/// <summary>
/// Open a dialog prompt to select a file to process.
/// </summary>
private void browseButton_Click(object sender, RoutedEventArgs e)
{
Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
dlg.Filter = "All Files|*.*";
Nullable<bool> result = dlg.ShowDialog();
if (result == true)
{
queryTB.Text = dlg.FileName;
}
}
private void pluginsLB_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
resultsDG.ItemsSource = resultsDS.Tables[pluginsLB.SelectedValue.ToString()].DefaultView;
}
}
}
答案 0 :(得分:2)
以下是我编写Result
方法的方法:
public System.IObservable<string> Result(
string input, string type, bool sensitive)
{
return Observable.Start(() =>
{
var csv = "\"Roundtrip Time\",\"Status\"\n";
if (sensitive == true)
{
csv += "\"\",\"FORBIDDEN\"\n";
}
else
{
var input2 = type == "URL" ? new Uri(input).Host : input;
ver ping = new Ping();
ver pingReply = ping.Send(input2);
csv += String.Format("\"{0}\",\"{1}\"\n",
pingReply.RoundtripTime, pingReply.Status);
}
return csv;
});
}
使用Rx为您的插件编写代码的最佳方法是确保尽可能多地保留在可观察的内容中 - 在生命的早期将数据变为可观察的数据,并且只能在生命的后期出现在可观察的数据中尽可能。然后一切都应该很好地融合在一起。
这有帮助吗?