解决JSON文件存在却触发FileNotFoundException的问题
Let's break down your problem and fix it step by step—you're hitting a common Xamarin pitfall with file paths, plus a couple of code details that need tweaking:
1. First: Fix Your Data Model (Critical Mistake)
You're using List<File> to deserialize your JSON, but System.IO.File is a built-in class for file operations, not a model for your place data. You need to create a custom class that matches your JSON structure (note the typo Adress/Address in your JSON—we'll handle that too):
using Newtonsoft.Json; namespace Orbage { public class Place { public string Label { get; set; } // Handle both "Adress" (typo) and "Address" from your JSON [JsonProperty("Address")] public string Address { get; set; } [JsonProperty("Adress")] public string AlternateAddress { set => Address = value; // Map the typo'd field to the correct property } public string Lat { get; set; } public string Lng { get; set; } } }
Then update your deserialization line to use this class:
var places = JsonConvert.DeserializeObject<List<Place>>(json);
2. Fix the FileNotFoundException (Core Problem)
Xamarin doesn't use simple relative paths like "File.json"—you need to account for platform-specific file locations and resource settings. Here are the most common solutions:
Option A: Embed the JSON as a Project Resource
- Setup: Right-click your
DATA.jsonfile in your shared/PCL project → Properties → Set Build Action toEmbedded Resource. - Reading Code:
var assembly = typeof(MapPage).GetTypeInfo().Assembly; // Replace "Orbage.DATA.json" with your project namespace + file path (e.g., if in a subfolder: "Orbage.Folder.DATA.json") using (Stream stream = assembly.GetManifestResourceStream("Orbage.DATA.json")) using (StreamReader reader = new StreamReader(stream)) { var json = reader.ReadToEnd(); var places = JsonConvert.DeserializeObject<List<Place>>(json); // Rest of your pin logic... }
Option B: Place the File in Platform-Specific Folders
For Android:
- Setup: Move
DATA.jsonto your Android project'sAssetsfolder → Right-click → Properties → Set Build Action toAndroidAsset. - Reading Code:
using (StreamReader reader = new StreamReader(Android.App.Application.Context.Assets.Open("DATA.json"))) { var json = reader.ReadToEnd(); var places = JsonConvert.DeserializeObject<List<Place>>(json); // Rest of your pin logic... }
For iOS:
- Setup: Move
DATA.jsonto your iOS project'sResourcesfolder → Right-click → Properties → Set Build Action toBundleResource. - Reading Code:
var filePath = Path.Combine(NSBundle.MainBundle.BundlePath, "DATA.json"); var json = File.ReadAllText(filePath); var places = JsonConvert.DeserializeObject<List<Place>>(json); // Rest of your pin logic... }
3. Fix Pin & Map Logic Issues
Your current loop overwrites CustomPins every iteration and moves the map multiple times—fix that:
public MapPage() { CustomMap customMap = new CustomMap { MapType = MapType.Street }; // Initialize the CustomPins list once customMap.CustomPins = new List<CustomPin>(); // ... (add your file reading/deserialization code here) foreach (var place in places) { if (double.TryParse(place.Lat, out double lat) && double.TryParse(place.Lng, out double lng)) { CustomPin pin = new CustomPin { Type = PinType.Place, Position = new Position(lat, lng), Label = place.Label, Address = place.Address, Name = "Xamarin", Url = "http://xamarin.com/about/" }; customMap.CustomPins.Add(pin); customMap.Pins.Add(pin); } } // Move the map once after adding all pins customMap.MoveToRegion(MapSpan.FromCenterAndRadius(new Position(37.79752, -122.40183), Distance.FromMiles(1.0))); Content = customMap; }
- Added
double.TryParseto avoid crashes if Lat/Lng values are invalid - Moved
Content = customMapto the end (optional but cleaner) - Fixed
CustomPinsto add pins instead of overwriting the list each time - Moved
MoveToRegionoutside the loop so it only runs once
内容的提问来源于stack exchange,提问作者ItsRaptorman

