WindowsPhoneアプリケーションに使用しているポータブルライブラリがあります。同じポータブルライブラリに、いくつかのコンテンツファイルがあります(ビルドアクション = コンテンツ)。
ポータブルライブラリにクラスDataReader
を作成しました。これは、コンテンツファイルにストリームを返すことになっています。ただし、以下のコードでは、一貫してnull
からGetManifestResourceStream
を取得しています。私は何が間違っているのですか?
public class DataReader
{
public static Stream GetStream(string code)
{
string path = string.Format("./data/code-{0}.dat", code);
return Assembly.GetExecutingAssembly().GetManifestResourceStream(path);
}
}
あなたの道は間違っています。スラッシュを使用していますが、埋め込まれたマニフェストリソース名では、ビルド中にスラッシュがピリオドに変換されました。また、PCLを対象とするプラットフォームによっては、Assembly.GetExecutingAssembly()
を呼び出すことさえできない場合があります。
これがあなたができることです:
var Assembly = typeof(AnyTypeInYourAssembly).GetTypeInfo().Assembly;
// Use this help aid to figure out what the actual manifest resource name is.
string[] resources = Assembly.GetManifestResourceNames();
// Once you figure out the name, pass it in as the argument here.
Stream stream = Assembly.GetManifestResourceStream("Some.Path.AndFileName.Ext");
ファイルアクセスは、WindowsStoreアプリとWindowsPhone8アプリの間で移植可能に行うことはできません。ファイルを開いてストリームを取得するには、プラットフォーム固有のコードを使用する必要があります。その後、ストリームをPCLに渡すことができます。
コンテンツビルドアクションを使用してビルドする場合、XMLはDLL内にありません。これはファイルシステム上にあり、PCLの内部から取得する方法はありません。そのため、すべての回答でビルドアクションがEmbedded Resourceに設定されています。ファイルをMyPCL.DLL\Path\To\Content.xml
内に配置します。
ただし、ビルドアクションをContentに設定し、コピーを設定した場合toCopy if newerと入力すると、ファイルは実行可能ファイルと同じディレクトリに配置されます。
したがって、PCLにファイルを読み取るためのインターフェイスを配置するだけです。移植性のないコードの起動時に、PCLに実装を挿入します。
namespace TestPCLContent
{
public interface IContentProvider
{
string LoadContent(string relativePath);
}
}
namespace TestPCLContent
{
public class TestPCLContent
{
private IContentProvider _ContentProvider;
public IContentProvider ContentProvider
{
get
{
return _ContentProvider;
}
set
{
_ContentProvider = value;
}
}
public string GetContent()
{
return _ContentProvider.LoadContent(@"Content\buildcontent.xml");
}
}
}
PCLが上で定義されたので、移植性のないコード(下)でインターフェース実装を作成できます。
namespace WPFBuildContentTest
{
class ContentProviderImplementation : IContentProvider
{
private static Assembly _CurrentAssembly;
private Assembly CurrentAssembly
{
get
{
if (_CurrentAssembly == null)
{
_CurrentAssembly = System.Reflection.Assembly.GetExecutingAssembly();
}
return _CurrentAssembly;
}
}
public string LoadContent(string relativePath)
{
string localXMLUrl = Path.Combine(Path.GetDirectoryName(CurrentAssembly.GetName().CodeBase), relativePath);
return File.ReadAllText(new Uri(localXMLUrl).LocalPath);
}
}
}
アプリケーションの起動時に、実装を挿入し、コンテンツの読み込みを示します。
namespace WPFBuildContentTest
{
//App entrance point. In this case, a WPF Window
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
ContentProviderImplementation cpi = new ContentProviderImplementation();
TestPCLContent.TestPCLContent tpc = new TestPCLContent.TestPCLContent();
tpc.ContentProvider = cpi; //injection
string content = tpc.GetContent(); //loading
}
}
}
EDIT:わかりやすくするために、Streamsではなく文字列のままにしました。
バウンティリクエストに応答するだけです。まず、ビルドアクション=コンテンツを使用しても、実際にはビルドにはまったく影響しません。これは、他のツールが読み取ることができるプロジェクトアイテムのプロパティです。インストーラービルダーは、たとえば、ファイルをセットアッププログラムに含めて、ユーザーのマシンに展開する必要があることを理解するためにそれを使用します。
賛成の質問で述べたように、ビルドアクション=組み込みリソースの使用はOPの監視でした。これは実際には、Assembly.GetManifestResourceStream()を使用してファイルをリソースとしてアセンブリマニフェストに埋め込むようにMSBuildに指示し、実行時にファイルを取得します。
しかし、賞金のコメントから、あなたもそれを望まないことはかなり明らかです。フォールバックは、ファイルをターゲットマシンにコピーすることです。あなたがそれを必要とするまでそれが辛抱強く座るところ。これは、ユーザーがストアからダウンロードするパッケージのサイズを変更しないnotであることに注意してください。アセンブリ内であろうとパッケージ内の別のファイルであろうと、同じ量のスペースが必要です。
だから、先に進む方法としてそれをスクラッチします。
実行時に違いが生じます。アセンブリが読み込まれると、アセンブリ全体が仮想メモリにマップされます。したがって、リソースを使用したアセンブリは、より多くの仮想メモリスペースを必要とします。しかし、「仮想」という言葉は非常に重要であり、電話のリソースはほとんど必要ありません。リソース内の4096バイトごとに、ページマッピングテーブル内のわずか数バイト。仮想メモリがアクセスされるまで、仮想メモリの支払いを開始しません。その時点で、電話のオペレーティングシステムは実際に仮想メモリから物理メモリに変換する必要があります。つまり、リソースのバイトをRAMにロードします。これはファイルのロードと同じで、ファイルを開くとRAMにもロードされます。
だから、先に進む方法としてそれをスクラッチします。
実際にこれを行う正当な理由が不足しています。Microsoftは確かに、リソースを処理するためのデフォルトの方法をベストプラクティスとして選択しました。です。ただし、コンテンツが大きすぎるという理由だけで、コンテンツをファイルとしてデプロイする必要がある場合があります。 2ギガバイト以上をプッシュし、32ビットオペレーティングシステム上のすべての仮想メモリを消費するため、VMにマップできない可能性があります。プログラムは単に開始できなくなります。これは、電話ユーザーが本当に喜ぶような種類のプログラムではありません。
次に、ソリューションのパッキング構築フェーズに焦点を当てる必要があります。これは、電話アプリが構築される最後のステップです。ソリューション内のすべてのプロジェクトがコンパイルされ、ストアにアップロードされ、ユーザーによってダウンロードされる唯一のファイルが作成されたもの。
はい、そこには問題があります。MSBuildは、リソースを使用しているPCLライブラリを表示するほどスマートではありません。ビルドアクション=インストーラーの場合と同様に、コンテンツは十分に優れているはずですが、それは機能しません。 のみDLLをパッケージ化し、リソースはパッケージ化しません。これは、ベストプラクティスソリューションである埋め込みを想定して作成されました。
あなたがしなければならないことは、パッケージマニフェストをオーバーライドすることです。 このMSDNの記事 で説明されています。非常に、非常に醜い、空白の点滅カーソルを見ています。それは私が良いアドバイスを使い果たしているところです、これはそうしないように作られました。
ファイルをポータブルリソースに追加し、ビルドアクションを埋め込みリソースに設定します。たとえば、フォルダCountryFlags
の下にあるファイルGB.png
、US.png
。
このようなコードでgetter関数を追加します(ここでは、countryflag getterイメージに固有です)。
public class CountryFlags {
public static Stream GetFlagStream(string countryIsoCode2ch)
{
var flagname = "Full.DLL.Name.CountryFlags.{0}.png";
var rs = Assembly.GetExecutingAssembly().GetManifestResourceStream(
string.Format(flagname, countryIsoCode2ch));
return rs;
}
}
ここで、Full.DLL.Name
は、.dll
拡張子の前にある生成されたポータブルライブラリの一部です。 (注:Anything.Resources.dll
は、少なくともXAPなどを生成するときにVisual Studioによって無視されるため、ライブラリの名前としては不適切です。代わりに、たとえばAnything.PortableResource.dll
が機能します)。
まず、次のようにアセンブリを取得します(DataLoaderはPCLアセンブリのクラスです):
var Assembly = typeof(DataLoader).GetTypeInfo().Assembly;
ファイルをポータブルリソースに追加し、ビルドアクションを埋め込みリソースに設定。
次に、次のようにリソースを取得できます。
string resourceNam= "to be filled";
var Assembly = typeof(DataLoader).GetTypeInfo().Assembly;
var compressedStream = Assembly.GetManifestResourceStream(resourceName));
たとえば、アセンブリ「TvShowTracker.Helpers」のフォルダ「Assets/Logos」にファイルlogo.pngがある場合、次のコードを使用します。
string resourceNam= "TvShowTracker.Helpers.Assets.Logos.logo.png";
var Assembly = typeof(DataLoader).GetTypeInfo().Assembly;
var compressedStream = Assembly.GetManifestResourceStream(resourceName));
ハッピーコーディング:)
var Assembly = typeof(PegHelper).GetTypeInfo().Assembly;
using (var stream = Assembly.GetManifestResourceStream("Parsers.Peg.SelfDef.xml"))
using (var reader = new StreamReader(stream))
{
string xmlText = reader.ReadToEnd();
return XDocument.Parse(xmlText);
}
リソースとしてファイルを追加した場合は、.Designer.csを確認してください。各リソースのプロパティがあります。そこからアクセスできます。
これは、datファイルリソースのサンプル自動生成プロパティです。
internal static byte[] MyDatFile {
get {
object obj = ResourceManager.GetObject("MyDatFile", resourceCulture);
return ((byte[])(obj));
}
datファイルは次のように読み取ることができます
System.Text.UTF8Encoding enc = new System.Text.UTF8Encoding();
var str = enc.GetString(Resource1.MyDatFile);