Xamarin iOS SqLite.SQLiteException CannotOpen

时间:2016-12-15 11:59:18

标签: c# sqlite xamarin xamarin.ios xamarin.forms

我是Xamarin(和C#)的新手,我的任务是编写基本上是网络扫描程序的东西。我正在使用Xamarin Forms,因为该应用程序应该适用于iOS和Android。

首先,我创建了一个SQLite.SQLiteException (CannotOpen)来存储通过ping网络上的设备生成的IP地址列表,但我现在正尝试将这些IP地址存储到SQLite数据库中。

我跟着Xamarin tutorial on the subject我已经能够合理地走得很远。我有它,所以它保存到Android上的数据库,然后显示在列表视图中(虽然我不是特别高兴我如何刷新列表视图的内容,但这是另一个问题)。

不幸的是,在iOS上,我无法获取数据库来存储值。每次尝试从扫描中添加第一个IP地址时,我都会得using System; using SQLite; using System.Linq; using System.Collections.ObjectModel; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; namespace ExampleUI { [Table("Device")] public class Device : IComparable, INotifyPropertyChanged { private int _id; [PrimaryKey, AutoIncrement] public int ID { get { return _id; } set { Debug.WriteLine("ID SET"); this._id = value; OnPropertyChanged(nameof(ID)); } } private string _ip; public string ip { get { return _ip; } set { Debug.WriteLine("IP SET"); this._ip = value; OnPropertyChanged(nameof(ip)); } } private string _mac; public string mac { get { return _mac; } set{ Debug.WriteLine("MAC SET"); this._mac = value; OnPropertyChanged(nameof(mac)); } } public event PropertyChangedEventHandler PropertyChanged; public Device() { } public Device(string ip, string mac) { this.ip = ip; this.mac = mac; } public int CompareTo(object obj) { Device device = obj as Device; if (device == null) { throw new ArgumentException("Object is not a Device"); } int lastOctet = 0; var octet = ip.Split('.').Last(); Int32.TryParse(octet, out lastOctet); int lastDeviceOctet = 0; var deviceOctet = device.ip.Split('.').Last(); if (Int32.TryParse(deviceOctet, out lastDeviceOctet) && Int32.TryParse(octet, out lastOctet)) { return lastOctet.CompareTo(lastDeviceOctet); } else { throw new ArgumentException("Last octet is not an integer"); } } protected virtual void OnPropertyChanged(string propertyName) { var changed = PropertyChanged; if (changed != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } } } 。我正在使用GBPing库(使用Xamarin绑定)来执行ping操作。

在我开始运行扫描之前,我添加了对insert方法的调用,并且添加了很多。我不知道为什么它不能在后续实例中成功运行。

我的数据模型类是:

using System;
using SQLite;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using Xamarin.Forms;
using System.Diagnostics;
using System.ComponentModel;

namespace ExampleUI
{
    public class DeviceDatabase: INotifyPropertyChanged
    {
        static object locker = new object();

        SQLiteConnection database;

        private ObservableCollection<Device> _devices;

        public ObservableCollection<Device> devices {
            get {
                this._devices.Sort();
                return this._devices;
            }
            set
            {
                Debug.WriteLine("SETTING OBSERVABLE COLLECTION");
                this._devices = value;
                OnPropertyChanged("devices");
            }
            }

        public DeviceDatabase()
        {
            database = DependencyService.Get<ISQLite>().GetConnection();
            Debug.WriteLine(database);
            database.CreateTable<Device>();
            this._devices = new ObservableCollection<Device>(database.Table<Device>());
            Debug.WriteLine("NO OF DEVICES IN COLLECTION:");
            Debug.WriteLine(_devices.Count);
            this._devices.CollectionChanged += _devices_CollectionChanged;
        }

        public ObservableCollection<Device> GetDevices()
        {
            lock (locker)
            {
                Debug.WriteLine("RETURNING LIST OF DEVICES");
                List<Device> collection = database.Table<Device>().ToList();
                ObservableCollection<Device> devicecollection = new ObservableCollection<Device>(collection);
                devicecollection.Sort();
                return devicecollection;
            }
        }

        public Device GetDevice(int id)
        {
            lock (locker)
            {
                return database.Table<Device>().FirstOrDefault(x => x.ID == id);
            }
        }

        public int SaveDevice(Device item)
        {
            Debug.WriteLine("SAVE DEVICE TO DB");
            lock (locker)
            {
                if (item.ID != 0)
                {
                    database.Update(item);
                    return item.ID;
                }
                else {
                    Debug.WriteLine(database.DatabasePath);
                    var query = database.Table<Device>().Where(v => v.ip.Equals(item.ip));
                    if (query.Count() == 0)
                    {
                        return database.Insert(item);
                    }
                    return 1;

                }
            }
        }

        public int DeleteDevice(int id)
        {
            lock (locker)
            {
                return database.Delete<Device>(id);
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged(string propertyName)
        {
            var changed = PropertyChanged;
            if (changed != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        void _devices_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            Debug.WriteLine("_devices_CollectionChanged");
        }
    }
}

数据库类是:

App.xaml.cs

数据库在主using Xamarin.Forms; using Xamarin.Forms.Xaml; [assembly: XamlCompilation(XamlCompilationOptions.Compile)] namespace ExampleUI { public partial class App : Application { static DeviceDatabase database; public App() { MainPage = new NavigationPage(new DevicePage()); } public static DeviceDatabase Database { get { if (database == null) { database = new DeviceDatabase(); } return database; } } protected override void OnStart() { // Handle when your app starts } protected override void OnSleep() { // Handle when your app sleeps } protected override void OnResume() { // Handle when your app resumes } } } 文件中设置:

using System;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.Net;
using System.Linq;
using System.Text;
using Foundation;
using System.Collections.ObjectModel;
using GBPinger;
using ExampleUI;



namespace GBPingHelper
{

    static class Extensions
    {
        public static void Sort<T>(this ObservableCollection<T> collection) where T : IComparable
        {
            List<T> sorted = collection.OrderBy(x => x).ToList();
            for (int i = 0; i < sorted.Count(); i++)
                collection.Move(collection.IndexOf(sorted[i]), i);
        }
    }

    public class PingHelper : GBPingDelegate
    {
        ObservableCollection<ExampleUI.Device> _devices { get; set; }

        int currentPingers;

        public delegate void DeviceScanCompleteHandler(object sender, PingArgs e);
        public delegate void DeviceAddedHandler(object sender, PingArgs e);

        public static event DeviceScanCompleteHandler DeviceScanComplete;
        public static event DeviceAddedHandler DeviceAdded;

        [DllImport(ObjCRuntime.Constants.SystemLibrary)]
        static internal extern int sysctl([MarshalAs(UnmanagedType.LPArray)] int[] mib, int mibsize, IntPtr output, IntPtr oldLen, IntPtr newp, uint newlen);

        public static Dictionary<String, String> AllMac = null;

        public PingHelper()
        {
            _devices = new ObservableCollection<Device>();
            currentPingers = 0;
        }

        public ObservableCollection<Device> Devices()
        {
            Console.WriteLine("HERE???? {0}", _devices.Count);
            return _devices;
        }

        public void pingSubnet(string subnet)
        {
            currentPingers = 0;
            for (int i = 1; i < 255; i++)
            {
                string ip = subnet + "." + i.ToString();
                Console.WriteLine("IP IS: {0}", ip);
                GBPing pinger = new GBPing();
                pinger.Host = ip;
                pinger.Delegate = this;
                pinger.Timeout = 1.0;
                pinger.PingPeriod = 1.0;

                pinger.SetupWithBlock((success, error) =>
                {
                    if (success)
                    {
                        pinger.StartPinging();
                        currentPingers += 1;
                        Console.WriteLine("Started...");
                        NSTimer.CreateScheduledTimer(TimeSpan.FromSeconds(5.0), delegate
                        {
                            pinger.Stop();
                            currentPingers -= 1;
                            pinger = null;
                            if (currentPingers == 0)
                            {
                                PingArgs args = new PingArgs();
                                args.Devices = Devices();
                                DeviceScanComplete(this, args);
                            }
                        });

                    }
                    else {
                        Console.WriteLine("Failed to start");
                    }
                });
            }
        }

        //delegate methods
        public override void DidFailWithError(GBPing pinger, NSError error)
        {
            Console.WriteLine("DidFailWithError {0}", error.ToString());
        }

        public override void DidSendPingWithSummary(GBPing pinger, GBPingSummary summary)
        {
            Console.WriteLine("DidSendPingWithSummary {0}", summary.Host);
        }

        public override void DidFailToSendPingWithSummary(GBPing pinger, GBPingSummary summary, NSError error)
        {
            Console.WriteLine("DidFailToSendPingWithSummary {0}", summary.Host);
        }

        public override void DidTimeoutWithSummary(GBPing pinger, GBPingSummary summary)
        {
            Console.WriteLine("DidTimeoutWithSummary {0}", summary.Host);
        }

        public override void DidReceiveReplyWithSummary(GBPing pinger, GBPingSummary summary)
        {
            Console.WriteLine("DidReceiveReplyWithSummary {0}", summary.Host);

            Dictionary<string, string> searchPattern = new Dictionary<string, string>();
            searchPattern.Add("ip", summary.Host);

            var device = Devices().FirstOrDefault(o => o.ip == summary.Host);
            Console.WriteLine("THE DEVICE IS: {0}", device);
            if (device == null)
            {

                Device deviceDetails = new Device(summary.Host, GetMACAddressByIp(summary.Host));
                //_devices.Add(deviceDetails);
                //_devices.Sort();
                Console.WriteLine("ADDED DEVICE: {0}", _devices.Count);
                //notify that a new device has been found
                PingArgs args = new PingArgs();
                args.Devices = new ObservableCollection<Device>();
                args.Devices.Add(deviceDetails);
                DeviceAdded(this, args);
            }
        }

        public override void DidReceiveUnexpectedReplyWithSummary(GBPing pinger, GBPingSummary summary)
        {
            Console.WriteLine("DidReceiveUnexpectedReplyWithSummary {0}", summary.Host);
        }

        //mac address methods

        public static String GetMACAddressByIp(String ip)
        {
            return GetMACAddressByIp(ip, false);
        }

        public static String GetMACAddressByIp(String ip, bool reset)
        {
            try
            {
                if (AllMac == null || reset)
                {
                    AllMac = new Dictionary<string, string>();
                    int CTL_NET = 4;
                    int PF_ROUTE = 17;
                    int AF_INET = 2;
                    int NET_RT_FLAGS = 2;
                    int RTF_LLINFO = 0x400;
                    int[] mib = { CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_LLINFO };
                    var pLen = Marshal.AllocHGlobal(sizeof(int));
                    sysctl(mib, 6, IntPtr.Zero, pLen, IntPtr.Zero, 0);
                    var length = Marshal.ReadInt32(pLen);
                    if (length == 0)
                    {
                        Marshal.FreeHGlobal(pLen);
                        return string.Empty;
                    }
                    var pBuf = Marshal.AllocHGlobal(length);
                    sysctl(mib, 6, pBuf, pLen, IntPtr.Zero, 0);
                    int off = 0;
                    while (true)
                    {
                        short len = Marshal.ReadInt16(pBuf + off);
                        IntPtr paddr = pBuf + off + 36 + 56;
                        byte sinlen = Marshal.ReadByte(paddr);
                        uint addr = (uint)Marshal.ReadInt32(paddr + 4);
                        string ipAddress = new IPAddress(BitConverter.GetBytes(addr)).ToString();
                        paddr += sinlen;
                        StringBuilder sb = new StringBuilder();
                        bool allZero = true;
                        for (int m = 0; m < 6; m++)
                        {
                            byte b = Marshal.ReadByte(paddr + 8 + m);
                            if (b != 0)
                            {
                                allZero = false;
                            }
                            if (sb.Length > 0)
                            {
                                sb.Append(":");
                            }
                            sb.Append(b.ToString("X2"));
                        }

                        String mac = sb.ToString();
                        if (!allZero)
                        {
                            AllMac[ipAddress] = mac;
                        }
                        off += len;
                        if (length <= off)
                        {
                            break;
                        }
                    }
                    Marshal.FreeHGlobal(pLen);
                    Marshal.FreeHGlobal(pBuf);
                }
                if (AllMac.ContainsKey(ip))
                {
                    return AllMac[ip];
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Exception in GetMACAddressByIp:" + ex.ToString());
            }
            return "";
        }


    }
}

我在PingHelper类中使用了GBPing:

App.Database.SaveDevice

这用于IPAddressManager接口的iOS实现(这是调用DeviceAdded的地方(参见方法using ExampleUI.iOS; using Xamarin.Forms; using System.Net.NetworkInformation; using System.Collections.Generic; using System.Collections.ObjectModel; using GBPingHelper; using System.Linq; [assembly: Dependency(typeof(IPAddressManager))] namespace ExampleUI.iOS { public class IPAddressManager : IIPAddressManager { PingHelper helper; public event EventHandler<PingArgs> DeviceCollectionUpdated; public event EventHandler DeviceCollectionScanStarted; public event EventHandler DeviceCollectionScanComplete; public IPAddressManager() { helper = new PingHelper(); PingHelper.DeviceScanComplete += DeviceScanCompleted; PingHelper.DeviceAdded += DeviceAdded; } public String GetIPAddress() { String ipAddress = ""; foreach (var netInterface in NetworkInterface.GetAllNetworkInterfaces()) { if (netInterface.NetworkInterfaceType == NetworkInterfaceType.Wireless80211 || netInterface.NetworkInterfaceType == NetworkInterfaceType.Ethernet) { foreach (var addrInfo in netInterface.GetIPProperties().UnicastAddresses) { if (addrInfo.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork) { ipAddress = addrInfo.Address.ToString(); } } } } return ipAddress; } public ObservableCollection<ExampleUI.Device> Devices() { return helper.Devices(); } public void PingSubnet() { DeviceCollectionScanStarted(this, EventArgs.Empty); string ipaddress = GetIPAddress(); string[] octets = ipaddress.Split('.'); var subnetOctets = octets.Take(octets.Length - 1); String subnetString = String.Join(".", subnetOctets); helper.pingSubnet(subnetString); } public void DeviceScanCompleted(Object sender, PingArgs args) { Console.WriteLine("HERE AT LAST {0}", args.Devices); DeviceCollectionScanComplete(this, EventArgs.Empty); } public void DeviceAdded(Object sender, PingArgs args) { Console.WriteLine("ADDRESS ADDED {0}", args.Devices[0].ip); App.Database.SaveDevice(args.Devices[0]); DeviceCollectionUpdated(this, args); } } } ):

ListView

绑定到App.Database.SaveDevice值的视图模型是(注意我在构造函数中调用了using System; using System.Diagnostics; using System.ComponentModel; using System.Collections.Generic; using System.Collections.ObjectModel; using Xamarin.Forms; using Xamarin.Forms.Xaml; namespace ExampleUI { public class MainPageViewModel: INotifyPropertyChanged { bool isLoading; bool isRefreshing; bool devicePresent; private Command refreshDeviceCommand; public Command RefreshDeviceCommand { get { return refreshDeviceCommand ?? (refreshDeviceCommand = new Command(ExecuteRefreshDeviceCommand, () => { return !IsRefreshing; })); } } public bool IsLoading { get { return isLoading; } set { isLoading = value; OnPropertyChanged("IsLoading"); } } public bool IsRefreshing { get { return isRefreshing; } set { isRefreshing = value; Debug.WriteLine("SETTING REFRESHING TO {0}", value); OnPropertyChanged("IsRefreshing"); } } public bool DevicePresent { get { return devicePresent; } set { devicePresent = value; OnPropertyChanged("DevicePresent"); } } private ObservableCollection<Device> _devices; public ObservableCollection<Device> Devices { get { return this._devices; } set { this._devices = value; OnPropertyChanged("Devices"); } } //public ObservableCollection<Device> Devices //{ // get // { // //return DependencyService.Get<IIPAddressManager>().Devices(); // return App.Database.devices; // } //} public MainPageViewModel() { IsLoading = true; IsRefreshing = false; DevicePresent = false; DependencyService.Get<IIPAddressManager>().DeviceCollectionUpdated += DeviceCollectionUpdated; DependencyService.Get<IIPAddressManager>().DeviceCollectionScanComplete += DeviceCollectionScanComplete; //Devices = App.Database.devices; Devices = App.Database.GetDevices(); App.Database.SaveDevice(new Device("192.168.0.1", "00:00")); } public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged(string propertyName) { var changed = PropertyChanged; if (changed != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } private void ExecuteRefreshDeviceCommand() { Debug.WriteLine("ExecuteRefreshDeviceCommand"); Debug.WriteLine(isRefreshing); if (IsRefreshing) { IsRefreshing = true; Debug.WriteLine("WILL REFRESH"); DependencyService.Get<IIPAddressManager>().PingSubnet(); } } void DeviceCollectionUpdated(object sender, PingArgs args) { Debug.WriteLine("DEVICE COLLECTION UPDATED"); IsLoading = false; DevicePresent = true; } void DeviceCollectionScanComplete(object sender, EventArgs args) { Debug.WriteLine("DEVICE COLLECTION SCAN COMPLETE"); IsLoading = false; DevicePresent = true; IsRefreshing = false; Devices = App.Database.GetDevices(); } } ,工作正常:

using System;
using System.IO;
using Xamarin.Forms;
using ExampleUI.iOS;
using SQLite;
using Foundation;

[assembly: Dependency(typeof(SQLite_iOS))]
namespace ExampleUI.iOS
{
    public class SQLite_iOS: ISQLite
    {
        public SQLiteConnection GetConnection()
        {
            var sqliteFilename = "Device.db3";
            var docs = NSFileManager.DefaultManager.GetUrls(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomain.User)[0];
            string documentsPath = docs.Path;
            string libraryPath = Path.Combine(documentsPath, "..", "Library"); // Library folder
            var path = Path.Combine(libraryPath, sqliteFilename);
            Console.WriteLine(path);
            var conn = new SQLiteConnection(path);
            return conn;
        }
    }
}

异常捕获窗口如下所示:

enter image description here

ISQLite的iOS实现:

namespace MyGameBundle\Entity;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;

/**
 * Island
 *
 *
 * @ORM\Table(name="islands")
 * @ORM\Entity(repositoryClass="MyGameBundle\Repository\IslandRepository")
 */
class Island
{
/**
 * @var int
 *
 * @ORM\Column(name="id", type="integer")
 * @ORM\Id
 * @ORM\GeneratedValue(strategy="AUTO")
 */
private $id;

/**
 * @var int
 *
 * @ORM\Column(name="x", type="integer")
 */
private $x;

/**
 * @var int
 *
 * @ORM\Column(name="y", type="integer")
 */
private $y;

/**
 * @var Player
 *
 * @ORM\ManyToOne(targetEntity="MyGameBundle\Entity\Player", inversedBy="islands")
 * @ORM\JoinColumn(name="player_id", nullable=false)
 */
private $player;

/**
 * @var IslandResource[]
 *
 * @ORM\OneToMany(targetEntity="MyGameBundle\Entity\IslandResource", mappedBy="island")
 */
private $resources;

/**
 * @var IslandBuilding[]
 *
 * @ORM\OneToMany(targetEntity="MyGameBundle\Entity\IslandBuilding", mappedBy="island")
 */
private $buildings;

/**
 * @var IslandTroop[]
 *
 * @ORM\OneToMany(targetEntity="MyGameBundle\Entity\IslandTroop", mappedBy="island")
 */
private $troops;

/**
 * @var TroopProcess[]
 *
 * @ORM\OneToMany(targetEntity="MyGameBundle\Entity\TroopProcess", mappedBy="island")
 */
private $process;


public function __construct()
{
    $this->resources = new ArrayCollection();
    $this->buildings = new ArrayCollection();
    $this->troops = new ArrayCollection();
    $this->process = new ArrayCollection();
}

/**
 * Get id
 *
 * @return int
 */
public function getId()
{
    return $this->id;
}

/**
 * Set x
 *
 * @param integer $x
 *
 * @return Island
 */
public function setX($x)
{
    $this->x = $x;

    return $this;
}

/**
 * Get x
 *
 * @return int
 */
public function getX()
{
    return $this->x;
}

/**
 * Set y
 *
 * @param integer $y
 *
 * @return Island
 */
public function setY($y)
{
    $this->y = $y;

    return $this;
}

/**
 * Get y
 *
 * @return int
 */
public function getY()
{
    return $this->y;
}

/**
 * @return Player
 */
public function getPlayer()
{
    return $this->player;
}

/**
 * @param Player $player
 */
public function setPlayer(Player $player)
{
    $this->player = $player;
}

/**
 * @return IslandResource[]
 */
public function getResources()
{
    return $this->resources;
}

/**
 * @param IslandResource[] $resources
 */
public function setResources(array $resources)
{
    $this->resources = $resources;
}

/**
 * @return IslandBuilding[]
 */
public function getBuildings()
{
    return $this->buildings;
}

/**
 * @param IslandBuilding[] $buildings
 */
public function setBuildings(array $buildings)
{
    $this->buildings = $buildings;
}

/**
 * @return IslandTroop[]
 */
public function getTroops()
{
    return $this->troops;
}

/**
 * @param IslandTroop[] $troops
 */
public function setTroops(array $troops)
{
    $this->troops = $troops;
}

/**
 * @return TroopProcess[]
 */
public function getProcess()
{
    return $this->process;
}

/**
 * @param TroopProcess[] $process
 */
public function setProcess(array $process)
{
    $this->process = $process;
}
}

非常感谢您提供的任何帮助。

谢谢,

亚当。

0 个答案:

没有答案