The snippet below isn't summing the variables (int)winTemp and playerWIn. I've verified that both variables are assigned the correct value by printing to screen before calling createXML(). My theory is that you cannot evaluate equations while creating new XELEMENT's. Can anyone verify this?
new XElement("playerWin", (int)winTemp + playerWin),
If I do it outside of XElement, like the commented lines in saveXML(), it works as intended.
If the file did not exist - Excepted XML output should be Wins=10, Loss=1, Tie=0.
If the file was existed - Excepted XML output should be Wins=20, Loss=2, Tie=0.
Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using System.Text;
using System.IO;
using System.Threading.Tasks;
namespace Testing_LINQ_to_XML
{
class Program
{
static void Main()
{
Player p = new Player();
p.readXML();
p.toScreen();
p.saveXML();
p.readXML();
p.toScreen();
p.Exit();
}
}
public class Player
{
public string path;
public string playerName;
public int playerWin = 10;
public int playerLoss = 1;
public int playerTie = 0;
public int winTemp;
public int lossTemp;
public int tieTemp;
public Player()
{
Console.WriteLine("Enter player Name...");
playerName = Console.ReadLine();
Console.WriteLine("n: " + playerName);
getPath();
Console.WriteLine("p: " + path);
Console.ReadLine();
}
public string getPath()
{
path = (#"..\XML Saves\" + playerName + ".xml");
return path;
}
public void toScreen()
{
Console.WriteLine("\nYour Record Is:\n");
Console.WriteLine("Wins: " + playerWin);
Console.WriteLine("Losses: " + playerLoss);
Console.WriteLine("Ties: " + playerTie);
}
public void saveXML()
{
if (File.Exists(path))
{
readXML();
File.Delete(path);
//playerWin = (int)winTemp;
//playerLoss = (int)lossTemp;
//playerTie = (int)tieTemp;
createFile();
}
else
{
createFile();
}
}
public void createFile()
{
XDeclaration _obj = new XDeclaration("1.0", "utf-8", "");
XNamespace gameSaves = "gameSaves";
XElement fileNew = new XElement("Root",
new XElement("Player",
new XElement("playerName", playerName),
new XElement("Stats",
new XElement("playerWin", (int)winTemp + playerWin),
new XElement("playerLoss", (int)lossTemp + playerLoss),
new XElement("playerTie", (int)tieTemp + playerTie))));
fileNew.Save(path);
Console.WriteLine("Save created: " + path);
}
public void readXML()
{
if (File.Exists(path))
{
var winTemp = new XElement("playerWin", playerWin);
var lossTemp = new XElement("playerLoss", playerLoss);
var tieTemp = new XElement("playerTie", playerTie);
}
else
{
Console.WriteLine("\nYou don't have any stats to show yet. Get playing!!!");
}
}
public void Exit()
{
Console.WriteLine("Press any key to exit.");
Console.ReadLine();
}
}
}
XML output:
<Root>
<Player>
<playerName>Name</playerName>
<Stats>
<playerWin>10</playerWin>
<playerLoss>1</playerLoss>
<playerTie>0</playerTie>
</Stats>
</Player>
</Root>
The locally scoped winTemp variable is hiding the instance variable (inside readXML() method). Thus winTemp instance variable does not get set at all and holds the default value, i.e. 0, by the time of addition.
Related
I've been trying to parse and search for a specific word in a big string, but I can't seem to be able to figure it out. I have created a script that connects a Twitch Channel's chat into unity.
An example of a message would be:
"#badge-info=subscriber/4;badges=moderator/1,subscriber/3,bits/1;bits=1;color=;display-name=TwitchUser1234;emotes=;flags=;id=da6ec4c6-af61-4346-abc-123456789;mod=1;room-id=12345678;subscriber=1;tmi-sent-ts=160987654321;turbo=0;user-id=123456789;user-type=mod :TwitchUser1234#TwitchUser1234.tmi.twitch.tv PRIVMSG #thechannelyouarewatching :PogChamp1 Another Test Bit"
I tried parsing and searching for the string 'bits' the message by doing:
private void GameInputs(string ChatInputs)
{
string Search;
Search = ChatInputs.Split(";", "=");
if(string "bits" in Search)
{
print("I made it here.");
}
}
I'm at a complete loss and have no idea how to do this. Any help is appreciated.
If my full code is needed it is:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using System.ComponentModel;
using System.Net.Sockets;
using System.IO;
public class TwitchChat : MonoBehaviour
{
private TcpClient twitchClient;
private StreamReader reader;
private StreamWriter writer;
public string username, password, channelName; // http://twitchapps.com/tmi
// Start is called before the first frame update
void Start()
{
Connect();
}
void Update()
{
if(!twitchClient.Connected)
{
Connect();
}
ReadChat();
}
private void Connect()
{
twitchClient = new TcpClient("irc.chat.twitch.tv", 6667);
reader = new StreamReader(twitchClient.GetStream());
writer = new StreamWriter(twitchClient.GetStream());
writer.WriteLine("PASS " + password);
writer.WriteLine("NICK " + username);
writer.WriteLine("USER " + username + " 8 * :" + username);
writer.WriteLine("JOIN #" + channelName);
writer.WriteLine("CAP REQ :twitch.tv/tags");
writer.Flush();
}
private void ReadChat()
{
if (twitchClient.Available > 0)
{
var message = reader.ReadLine();
print(message);
GameInputs(message);
}
}
private void GameInputs(string ChatInputs)
{
string Search;
Search = ChatInputs.Split(";", "=");
if(string "bits" in Search)
{
print("I made it here.");
}
}
}
If you want to pull the value of "bits=xx" out, this would do it:
var b = value.Split(';').FirstOrDefault(s => s.StartsWith("bits="))?[5..];
b will be null if "bits=" is not present
If you're going to parse a lot of values out of this string consider turning it into a dictionary:
var c = new []{'='};
var d = value.Split(';').ToDictionary(s => s.Split(c,2)[0], s => s.Split(c,2)[1]);
It's slightly inefficient to split twice, if it bothers you, you can sub string:
value.Split(';').ToDictionary(s => s[..s.IndexOf('=')], s => s[s.IndexOf('=')+1..]);
This gives a dictionary of string, so you can do like:
if(d.ContainsKey("bits")){
var bits = int.Parse(d["bits"]);
...
String has a method Contains(string) that does the job:
if (ChantInputs.Contains("bits")
{
print("I made it here.");
}
You can try below.
private void GameInputs(string ChatInputs)
{
string[] Search = ChatInputs.Split(new char[] { ';', '=' });
foreach(string s in Search)
{
if(s == "bits")
{
print("I made it here.");
}
}
}
Below is the working code.
using System;
namespace ConsoleApp3
{
class Program
{
static void Main(string[] args)
{
string str = "one;two;test;three;test+test";
string[] strs = str.Split(new char[] { ';', '+' });
foreach(string s in strs)
{
if(s == "test")
{
Console.WriteLine(s);
}
}
Console.ReadLine();
}
}
}
I am trying to create a couple of mock unit tests for my software test assignment and my GUI.cs file has an error that says it cannot implicitly convert type "System.Collections.IList" to "System.Collection.ArrayList"
this.accounts = database.GetAccounts();
However that file was untouched. By that I mean I didn't modify it. The only files I have modified are the unit test, the file database and the Idatabase, listed below, by changing some variable types such as renaming all my ArrayList to IList.
But my GUI has the error and I'm not able to figure out which file is the cause of it and which line of code.
Below is the GUI.cs file
The error is the "this.accounts..." line.
The two "dataGridView1" lines has some System.NullReferenceException error when I hover my mouse over it on Visual Studio. Could that be related to the error I'm having, I'm not so sure.
private void InitBankRead()
{
try
{
//database = new FileDatabase();
database = IoC.GetInstance().Resolve<IDatabase>();
this.accounts = database.GetAccounts();
this.dataGridView1.DataSource = accounts;
dataGridView1.Columns["Balance"].DefaultCellStyle.Format = "C";
foreach (DataGridViewColumn column in dataGridView1.Columns)
{
dataGridView1.Columns[column.Name].SortMode = DataGridViewColumnSortMode.Automatic;
}
}
=====================================================
=====================================================
EDIT:
Further down below are the rest of my files for anyone who wants to dig into it deeper. It's optional but it's there. My attempt is not to overwhelm you guys with the works I have, but to make sure you understand what I'm talking about.
IDatabase.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections;
using Banking;
namespace Banking
{
public interface IDatabase
{
//IList<Account> FindAll();
//Account FindByAccount(int accountId);
//Account FindByName(int firstName, int lastName);
//bool Save(Account target);
bool AddNewCustomer(int customerId, string firstName, string lastName, decimal openingDeposit, Account.ACCOUNTTYPE type);
bool UpdateExistingAccount(char transactionType, Account account, decimal amount);
IList GetAccounts();
}
}
FileDatabase.cs
using System;
using System.Collections;
using System.IO;
using Banking;
namespace Banking
{
public class FileDatabase : IDatabase
{
private string filename;
private StreamWriter outFile;
private StreamReader inFile;
public const string DELIMETER = ",";
public FileDatabase()
{
this.filename = #"..\..\..\Banking\Data\Database.txt";
}
public bool AddNewCustomer(int customerID, string firstName, string lastName, decimal openingDeposit, Account.ACCOUNTTYPE type)
{
int accountID = GetAccounts().Count + 1;
using (outFile = File.AppendText(filename))
{
string output = accountID + DELIMETER + customerID + DELIMETER + firstName + DELIMETER + lastName + DELIMETER + openingDeposit + DELIMETER + Convert.ToInt32(type);
outFile.WriteLine(output);
outFile.Close();
}
return true;
}
public bool UpdateExistingAccount(char transactionType, Account account, decimal amount)
{
bool success = false;
try
{
switch (transactionType)
{
case 'D':
//account.Balance += amount;
account.deposit(amount);
break;
case 'W':
//account.Balance -= amount;
account.withdrawl(amount);
break;
}
IList accounts = GetAccounts();
int accountID = account.AccountID;
// Find and replace the account
for (int i = 0; i < accounts.Count; ++i)
{
if (accountID == ((Account) accounts[i]).AccountID)
{
accounts[i] = account;
}
}
using (outFile = new StreamWriter(filename))
{
foreach (Account acct in accounts)
{
outFile.WriteLine(acct.AccountID + DELIMETER + acct.Customer.CustomerID + DELIMETER + acct.Customer.FirstName + DELIMETER + acct.Customer.LastName + DELIMETER + acct.Balance + DELIMETER + Convert.ToInt32(acct.AccountType));
}
outFile.Close();
}
success = true;
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
success = false;
}
return success;
}
public IList GetAccounts()
{
IList accounts = new ArrayList();
using (inFile = new StreamReader(filename))
{
int customerID;
int accountID;
string firstName;
string lastName;
decimal balance;
int accountType;
string line = string.Empty;
while ((line = inFile.ReadLine()) != null)
{
string [] data = line.Split(DELIMETER.ToCharArray()[0]);
customerID = Convert.ToInt32(data[0]);
accountID = Convert.ToInt32(data[1]);
firstName = Convert.ToString(data[2]);
lastName = Convert.ToString(data[3]);
balance = Convert.ToDecimal(data[4]);
accountType = Convert.ToInt32(data[5]);
Customer customer = new Customer(customerID, firstName, lastName);
Account account;
Account.ACCOUNTTYPE type = (Account.ACCOUNTTYPE) accountType;
if (type == Account.ACCOUNTTYPE.CHECKING)
{
account = new Checking(customer, accountID, Convert.ToDecimal(balance));
}
else
{
account = new Savings(customer, accountID, Convert.ToDecimal(balance));
}
accounts.Add(account);
}
inFile.Close();
}
return accounts;
}
}
}
UnitTest.cs
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Banking;
using Moq;
namespace UnitTestsWithMoQ
{
[TestClass]
public partial class UnitTest1
{
public TestContext TestContext { get; set; }
public readonly IDatabase MockDatabase;
private IList accounts = new List<Account>
{
new Checking( new Customer(1, "Alex", "Parrish"), 12, 30.00M ),
new Savings( new Customer(2, "Alex", "Russo"), 12, 29.00M ),
new Checking( new Customer(3, "Emma", "Swan"), 12, 30.00M ),
new Savings( new Customer(4, "Henry", "Mills"), 12, 30.00M )
};
Mock<IDatabase> dataMock = new Mock<IDatabase>();
private string filename;
private StreamWriter outFile;
private StreamReader inFile;
public const string DELIMETER = ",";
public UnitTest1()
{
// Return all accounts
dataMock.Setup(repository => repository.GetAccounts()).Returns(accounts);
dataMock.Setup(repository => repository.UpdateExistingAccount(It.IsAny<char>(), It.IsAny<Account>(),
It.IsAny<decimal>())).Returns((char transactionType, Account account, decimal amountDecimal) =>
{
bool success = false;
try
{
switch (transactionType)
{
case 'D':
//account.Balance += amount;
account.deposit(amountDecimal);
break;
case 'W':
//account.Balance -= amount;
account.withdrawl(amountDecimal);
break;
}
var accounts = MockDatabase.GetAccounts();
int accountID = account.AccountID;
// Find and replace the account
for (int i = 0; i < accounts.Count; ++i)
{
if (accountID == ((Account) accounts[i]).AccountID)
{
accounts[i] = account;
}
}
// Find and replace the account
for (int i = 0; i < accounts.Count; ++i)
{
MockDatabase.GetAccounts()[i] = accounts[i];
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
success = false;
}
return success;
});
dataMock.Setup(repository => repository.AddNewCustomer(It.IsAny<int>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<decimal>(),
It.IsAny<Account.ACCOUNTTYPE>())).Returns((int customerID, string firstName, string lastName, decimal openingDeposit, Account.ACCOUNTTYPE type) =>
{
int accountID = MockDatabase.GetAccounts().Count + 1;
using (outFile = File.AppendText(filename))
{
string output = accountID + DELIMETER + customerID + DELIMETER + firstName + DELIMETER + lastName + DELIMETER + openingDeposit + DELIMETER + Convert.ToInt32(type);
outFile.WriteLine(output);
outFile.Close();
}
return true;
});
MockDatabase = dataMock.Object;
}
}
}
If the error says cannot implicitly convert type "System.Collections.IList" to "System.Collection.ArrayList", you are then probably assigning an IList variable to an ArrayList variable.
Note that IList is an interface which is more generic than the concrete type ArrayList, so the compiler does not know how to convert it implicitly.
this.accounts = database.GetAccounts();
How is that accounts defined?
If it's defined as: ArrayList accounts then you will not be able to make that assignment.
Try changing it to: IList accounts
OK this is what I have. I have my main form frmMain.cs and I have a class.cs. I was doing an RSSFeed for my email and I get the error:
inaccessible due to its protective level.
On my class.cs I have the following code:
public class RSSFeed
{
public void CheckForEmails()
{
string GmailAtomUrl = "https://mail.google.com/mail/feed/atom";
XmlUrlResolver xmlResolver = new XmlUrlResolver();
xmlResolver.Credentials = new NetworkCredential(Settings.Default.GmailUser, Settings.Default.GmailPassword);
XmlTextReader xmlReader = new XmlTextReader(GmailAtomUrl);
xmlReader.XmlResolver = xmlResolver;
try
{
XNamespace ns = XNamespace.Get("http://purl.org/atom/ns#");
XDocument xmlFeed = XDocument.Load(xmlReader);
var emailItems = from item in xmlFeed.Descendants(ns + "entry")
select new
{
Author = item.Element(ns + "author").Element(ns + "name").Value,
Title = item.Element(ns + "title").Value,
Link = item.Element(ns + "link").Attribute("href").Value,
Summary = item.Element(ns + "summary").Value
};
frmMain.MsgList.Clear();
frmMain.MsgLink.Clear();
foreach (var item in emailItems)
{
if (item.Title == String.Empty)
{
frmMain.MsgList.Add("Message from " + item.Author + ", There is no subject and the summary reads, " + item.Summary);
frmMain.MsgLink.Add(item.Link);
}
else
{
frmMain.MsgList.Add("Message from " + item.Author + ", The subject is " + item.Title + " and the summary reads, " + item.Summary);
frmMain.MsgLink.Add(item.Link);
}
}
if (emailItems.Count() > 0)
{
if (emailItems.Count() == 1)
{
frmMain.lblEmail.Text = ("You have one new email, would you like me to read it to you");
}
else
{
frmMain.lblEmail.Text("You have " + emailItems.Count() + "new emails");
}
}
else if (frmMain.QEvent == "CheckForNewEmails" && emailItems.Count() == 0)
{
frmMain.lblEmail.Text("You have no new emails"); frmMain.QEvent = String.Empty;
}
}
catch
{
frmMain.lblEmail.Text("You have submitted invalid log in information");
}
}
}
And then I have on my main form a timer tick event:
public void tmrEmail_Tick(object sender, EventArgs e)
{
lblEmail.Text = ("New Emails " + RSSFeed.CheckForEmails);
}
What I am not understanding is when I have the label in my RSSFeed or on my main form timer tick. I get the error. I have changed everything to public and it still is throwing the error.
Am I missing something or do I not have everything I should have?
Also I am going to have another form that is just dedicated to email. Would it be better to do away with the RSSFeed.cs and just code the winform? The only thing this is doing is creating a label when I have new emails.
Any thoughts?
You are missing the static keyword from your class and method. Should be public static class RSSFeed and public static void CheckForEmails()
You need to pass an instance of the frmMain to the method too. E.g.:
public static void CheckForEmails(frmMain frmMainInstance)
Putting it all together:
public static class RSSFeed
{
public static void CheckForEmails(frmMain frmMainInstance)
{
string GmailAtomUrl = "https://mail.google.com/mail/feed/atom";
XmlUrlResolver xmlResolver = new XmlUrlResolver();
// ... rest of your code ...
}
}
And the call to it would be something like:
public void tmrEmail_Tick(object sender, EventArgs e)
{
// The following line will produce a compile error because
// CheckForEmails doesn't return a value
// lblEmail.Text = ("New Emails " + RSSFeed.CheckForEmails(this);
// Try this instead:
RSSFeed.CheckForEmails(this);
}
Note that I am assuming tmrEmail_Tick is a method in frmMain, hence I am passing this as the argument to CheckForEmails.
Instead of making RSSFeed and CheckForEmails static you could instantiate an instance of RSSFeed:
public void tmrEmail_Tick(object sender, EventArgs e)
{
RSSFeed feed = new RSSFeed();
feed.CheckForEmails(this);
}
Note that you still need to pass frmMain instance as an argument to CheckForEmails.
I'm trying to transfer data from a treenode (at least I think that's what it is) which contains much more data than I need. It would be very difficult for me to manipulate the data within the treenode. I would much rather have an array which provides me with only the necessary data for data manipulation.
I would like higher rates have following variables:
1. BookmarkNumber (integer)
2. Date (string)
3. DocumentType (string)
4. BookmarkPageNumberString (string)
5. BookmarkPageNumberInteger (integer)
I would like to the above defined rate from the data from variable book_mark (as can be seen in my code).
I've been wrestling with this for two days. Any help would be much appreciated. I'm probably sure that the question wasn't phrased correctly so please ask questions so that I may explain further if needed.
Thanks so much
BTW what I'm trying to do is create a Windows Form program which parses a PDF file which has multiple bookmarks into discrete PDF files for each bookmark/chapter while saving the bookmark in the correct folder with the correct naming convention, the folder and naming convention dependent upon the PDF name and title name of the bookmark/chapter being parsed.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
using itextsharp.pdfa;
using iTextSharp.awt;
using iTextSharp.testutils;
using iTextSharp.text;
using iTextSharp.xmp;
using iTextSharp.xtra;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void ChooseImageFileWrapper_Click(object sender, EventArgs e)
{
OpenFileDialog openFileDialog1 = new OpenFileDialog();
openFileDialog1.InitialDirectory = GlobalVariables.InitialDirectory;
openFileDialog1.Filter = "Pdf Files|*.pdf";
openFileDialog1.RestoreDirectory = true;
openFileDialog1.Title = "Image File Wrapper Chooser";
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
try
{
GlobalVariables.ImageFileWrapperPath = openFileDialog1.FileName;
}
catch (Exception ex)
{
MessageBox.Show("Error: Could not read file from disk. Original error: " + ex.Message);
}
}
ImageFileWrapperPath.Text = GlobalVariables.ImageFileWrapperPath;
}
private void ImageFileWrapperPath_TextChanged(object sender, EventArgs e)
{
}
private void button2_Click(object sender, EventArgs e)
{
iTextSharp.text.pdf.PdfReader pdfReader = new iTextSharp.text.pdf.PdfReader(GlobalVariables.ImageFileWrapperPath);
IList<Dictionary<string, object>> book_mark = iTextSharp.text.pdf.SimpleBookmark.GetBookmark(pdfReader);
List<ImageFileWrapperBookmarks> IFWBookmarks = new List<ImageFileWrapperBookmarks>();
foreach (Dictionary<string, object> bk in book_mark) // bk is a single instance of book_mark
{
ImageFileWrapperBookmarks.BookmarkNumber = ImageFileWrapperBookmarks.BookmarkNumber + 1;
foreach (KeyValuePair<string, object> kvr in bk) // kvr is the key/value in bk
{
if (kvr.Key == "Kids" || kvr.Key == "kids")
{
//create recursive program for children
}
else if (kvr.Key == "Title" || kvr.Key == "title")
{
}
else if (kvr.Key == "Page" || kvr.Key == "page")
{
}
}
}
MessageBox.Show(GlobalVariables.ImageFileWrapperPath);
}
}
}
Here's one way to parse a PDF and create a data structure similar to what you describe. First the data structure:
public class BookMark
{
static int _number;
public BookMark() { Number = ++_number; }
public int Number { get; private set; }
public string Title { get; set; }
public string PageNumberString { get; set; }
public int PageNumberInteger { get; set; }
public static void ResetNumber() { _number = 0; }
// bookmarks title may have illegal filename character(s)
public string GetFileName()
{
var fileTitle = Regex.Replace(
Regex.Replace(Title, #"\s+", "-"),
#"[^-\w]", ""
);
return string.Format("{0:D4}-{1}.pdf", Number, fileTitle);
}
}
A method to create a list of Bookmark (above):
List<BookMark> ParseBookMarks(IList<Dictionary<string, object>> bookmarks)
{
int page;
var result = new List<BookMark>();
foreach (var bookmark in bookmarks)
{
// add top-level bookmarks
var stringPage = bookmark["Page"].ToString();
if (Int32.TryParse(stringPage.Split()[0], out page))
{
result.Add(new BookMark() {
Title = bookmark["Title"].ToString(),
PageNumberString = stringPage,
PageNumberInteger = page
});
}
// recurse
if (bookmark.ContainsKey("Kids"))
{
var kids = bookmark["Kids"] as IList<Dictionary<string, object>>;
if (kids != null && kids.Count > 0)
{
result.AddRange(ParseBookMarks(kids));
}
}
}
return result;
}
Call method above like this to dump the results to a text file:
void DumpResults(string path)
{
using (var reader = new PdfReader(path))
{
// need this call to parse page numbers
reader.ConsolidateNamedDestinations();
var bookmarks = ParseBookMarks(SimpleBookmark.GetBookmark(reader));
var sb = new StringBuilder();
foreach (var bookmark in bookmarks)
{
sb.AppendLine(string.Format(
"{0, -4}{1, -100}{2, -25}{3}",
bookmark.Number, bookmark.Title,
bookmark.PageNumberString, bookmark.PageNumberInteger
));
}
File.WriteAllText(outputTextFile, sb.ToString());
}
}
The bigger problem is how to extract each Bookmark into a separate file. If every Bookmark starts a new page it's easy:
Iterate over the return value of ParseBookMarks()
Select a page range that begins with the current BookMark.Number, and ends with the next BookMark.Number - 1
Use that page range to create separate files.
Something like this:
void ProcessPdf(string path)
{
using (var reader = new PdfReader(path))
{
// need this call to parse page numbers
reader.ConsolidateNamedDestinations();
var bookmarks = ParseBookMarks(SimpleBookmark.GetBookmark(reader));
for (int i = 0; i < bookmarks.Count; ++i)
{
int page = bookmarks[i].PageNumberInteger;
int nextPage = i + 1 < bookmarks.Count
// if not top of page will be missing content
? bookmarks[i + 1].PageNumberInteger - 1
/* alternative is to potentially add redundant content:
? bookmarks[i + 1].PageNumberInteger
*/
: reader.NumberOfPages;
string range = string.Format("{0}-{1}", page, nextPage);
// DEMO!
if (i < 10)
{
var outputPath = Path.Combine(OUTPUT_DIR, bookmarks[i].GetFileName());
using (var readerCopy = new PdfReader(reader))
{
var number = bookmarks[i].Number;
readerCopy.SelectPages(range);
using (FileStream stream = new FileStream(outputPath, FileMode.Create))
{
using (var document = new Document())
{
using (var copy = new PdfCopy(document, stream))
{
document.Open();
int n = readerCopy.NumberOfPages;
for (int j = 0; j < n; )
{
copy.AddPage(copy.GetImportedPage(readerCopy, ++j));
}
}
}
}
}
}
}
}
}
The problem is that it's highly unlikely all bookmarks are going to be at the top of every page of the PDF. To see what I mean, experiment with commenting / uncommenting the bookmarks[i + 1].PageNumberInteger lines.
I'm running a windows application(x86) platform in a windows server 2012(x64) and I'm using a SubSonic to get data from the SQLserver.
And I got this error from try catch Exception
at SubSonic.SqlQuery.ExecuteAsCollectionListType at
CIS.Server.Automailer.Core.ReportConfig.getReportConfig() at
CIS.Server.Automailer.Automailer.processDownload() at
CIS.Server.Automailer.Program.Main()
Here's my source code:
Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.IO;
namespace CIS.Server.Automailer
{
static class Program
{
[STAThread]
static void Main()
{
try
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Automailer mailer = new Automailer();
mailer.processDownload();
Application.Run();
}
catch(Exception ex)
{
Log(ex);
}
}
static void Log(Exception ex)
{
string stackTrace = ex.StackTrace;
File.WriteAllText("trace.txt", stackTrace); // path of file where stack trace will be stored.
}
}
}
Automailer.cs
public void processDownload()
{
var data = ReportConfig.getReportConfig();
var machineCenterIds = data[0].MachineCenterId;
var reportIds = data[0].ReportId;
var email = data[0].Email;
recipient = email;
string[] splitRepId = reportIds.Split(',');
int[] repIds = new int[splitRepId.Length];
int c=0;
foreach (string repId in splitRepId)
{
repIds[c] = Convert.ToInt32(repId);
c++;
}
var reportNames = ReportConfig.getReportName(repIds);
string[] splitMcIds = machineCenterIds.Split(',');
int ctr = 0;
filePaths = new string[splitMcIds.Length * reportNames.Count()];
ei.processFinished = false;
foreach (string mcId in splitMcIds)
{
for (int i = 0; i < reportNames.Count(); i++)
{
string reportName = Convert.ToString(reportNames[i]);
string url = Utility.GetTemporaryURL(mcId, reportName);
string fileName = reportName.Replace(" ", "");// + "_" + j + "_00" + i
downloadPath = string.Format(configPath, mcId, fileName);
filePaths[ctr] = downloadPath;
GenerateMails(url);
Console.WriteLine(downloadPath);
ctr++;
}
}
processEmail();
ei.processFinished = true;
}
ReportConfig.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace CIS.Server.Automailer.Core
{
class ReportConfig
{
public static ReportAutomationCollection getReportConfig()
{
return DB.Select().From(ReportAutomation.Schema)
.Where(ReportAutomation.Columns.UserId).IsEqualTo("001111d6-cc2a-469a-a1bc-1ccd64e60a08")
.ExecuteAsCollection<ReportAutomationCollection>();
}
public static ReportTypeCollection getReportName(int[] reportId)
{
return DB.Select(ReportType.Columns.ReportName).From(ReportType.Schema)
.Where(ReportType.ReportIdColumn).In(reportId.ToString())
.ExecuteAsCollection<ReportTypeCollection>();
}
}
}
Seems like you have a problem with your database. since your access now is on the server.
check your data if both exist on your local and on the Server.