MailMerge if-statement with dynamic table inside - c#

I'm currently working on a MailMerge Word-docx. When we had the following, everything worked fine:
And the result was:
What we want is to not show this table if there aren't any Authorization-events, so I've changed it to the following:
With the following result:
As you can see, the table is now empty, even though there are AuthorizationEvents. Is it possible to somehow use a dynamic table inside an IF-MERGEFIELD? Is this is a bug in Aspose's MailMerging, or I'm simply doing something wrong?
PS: I know the MailMerge-synthax we use with the {{Something}} is less known than the <<Something>>, but they work the same. Just a heads-up since I had questions regarding the MailMerge-synthax in the past.
Here is the .NET code (although I doubt it's relevant for my issue):
public class PrintDto
{
public PrintDto(OurObject ourObject, ProcessTimeline processTimeline)
{
...
AutorisatieEvents = GetAutorisatieEvents(processTimeline);
HeeftAutorisatieEvents = AutorisatieEvents.Any();
}
...
public IList<AutorisatieEventDto> AutorisatieEvents { get; private set; }
public bool HeeftAutorisatieEvents { get; private set; }
}
AutorisatieEventDto:
public class AutorisatieEventDto
{
public string Happened { get; set; }
public string Event { get; set; }
public string Performer { get; set; }
public string Opmerking { get; set; }
}
MailMerging code:
public byte[] GenerateDocument(Stream template, DocumentDataSource dataSource)
{
var doc = new Document(template);
doc.MailMerge.UseNonMergeFields = true;
doc.MailMerge.CleanupOptions = MailMergeCleanupOptions.RemoveContainingFields |
MailMergeCleanupOptions.RemoveUnusedFields |
MailMergeCleanupOptions.RemoveUnusedRegions |
MailMergeCleanupOptions.RemoveEmptyParagraphs;
doc.ResourceLoadingCallback = new ImageLoadingHandler();
// Support html MailMerge-fields
doc.MailMerge.FieldMergingCallback = new HandleMergeFieldInsertHtml();
doc.MailMerge.Execute(dataSource);
doc.MailMerge.ExecuteWithRegions((IMailMergeDataSourceRoot) dataSource);
doc.UpdateFields();
using (var memoryStream = new MemoryStream())
{
doc.Save(memoryStream, SaveFormat.Pdf);
return memoryStream.ToArray();
}
Which is used in:
public byte[] CreatePrintAsBytes(PrintDto printData)
{
if (printData == null) throw new ArgumentNullException("printData");
var path = Path.Combine(_templatePath, "printdto.docx");
using (var fileStream = File.OpenRead(path))
{
var dataSource = new DocumentDataSource(printData);
return DocumentConverter.GenerateDocument(fileStream, dataSource);
}
}
And displayed like this:
[HttpGet]
public ActionResult Print(Guid id)
{
var ourObject = NhSession.GetByGuid<OurObject>(id);
var processTimeline = GetProcessTimelineOfOurObject(ourObject);
var printData = new PrintDto(ourObject, processTimeline);
var documentAsByteArray = _documentService.CreatePrintAsBytes(printData);
return File(documentAsByteArray, "application/pdf");
}

Related

How to use streams, to generate csv file, using CsvHelper in .NET Core 3.1?

I am developing an api, which has to return csv file on some endpoint. Here's my controller responsible for csv generation:
[ApiController]
[Route("api/[controller]")]
[Authorize]
public sealed class ReportController : BaseController
{
public ReportController(ICommandBus commandBus,
IQueryBus queryBus)
: base(commandBus, queryBus)
{
}
[HttpGet]
public async Task<IActionResult> GetReportAsync([FromQuery] GenerateReportRequest request)
{
try
{
var report = await QueryBus
.SendAsync<GenerateReportQuery, Report>(new GenerateReportQuery
{
Filters = request.Filters,
ResponseFileFormat = request.ResponseFileFormat,
WithPodOnly = request.WithPodOnly
});
return File(report.Content,
report.Type,
report.Name);
}
catch (Exception e)
{
// ToDo: Handle exception in proper way
return StatusCode(StatusCodes.Status500InternalServerError,
e.Message);
}
}
}
When the request comes to my api, certain handler is invoked, and the csv generation starts in CsvGenerationStrategy class, which is attached below:
public class CsvGenerationStrategy : IReportGenerationStrategy
{
public async Task<Report> GenerateReportAsync(ICollection<ShipmentEntity> shipmentEntities)
{
var shipment = shipmentEntities
.Select(s => (Shipment) s)
.ToList();
await using var memoryStream = new MemoryStream();
await using var streamWriter = new StreamWriter(memoryStream);
await using var csvWriter = new CsvWriter(streamWriter, CultureInfo.InvariantCulture);
csvWriter.Configuration.Delimiter = ";";
await csvWriter.WriteRecordsAsync(shipment);
var content = memoryStream.ToArray();
var report = new Report
{
Content = content,
Type = ReportConstants.CsvFileType,
Name = ReportConstants.CsvReportFileName
};
return report;
}
private class Shipment
{
[Name(ReportConstants.IssueColumnName)]
public string Issue { get; set; }
[Name(ReportConstants.MaterialReleaseReceiptColumnName)]
public string MaterialReleaseReceipt { get; set; }
[Name(ReportConstants.FreightBillIssueColumnName)]
public string FreightBillIssue { get; set; }
[Name(ReportConstants.InvoiceNumberColumnName)]
public string InvoiceNumber { get; set; }
[Name(ReportConstants.TaxCodeColumnName)]
public string TaxCode { get; set; }
[Name(ReportConstants.ContractorIdColumnName)]
public string ContractorId { get; set; }
[Name(ReportConstants.AddressIdColumnName)]
public string AddressId { get; set; }
[Name(ReportConstants.ContractorNameColumnName)]
public string ContractorName { get; set; }
[Name(ReportConstants.ShipmentCountryColumnName)]
public string ShipmentCountry { get; set; }
public static explicit operator Shipment(ShipmentEntity entity) =>
entity != null
? new Shipment
{
Issue = entity.Issue,
MaterialReleaseReceipt = entity.MaterialReleaseReceipt,
FreightBillIssue = entity.FreightBillIssue,
InvoiceNumber = entity.InvoiceNumber,
TaxCode = entity.TaxCode,
ContractorId = entity.ContractorId,
AddressId = entity.AddressId,
ContractorName = entity.ContractorName,
ShipmentCountry = entity.ShipmentCountry
}
: null;
}
}
The code looks properly, but the behavior of the class is quite strange. In most cases, the generation runs properly, but few times i have noticed a situation, when the MemoryStream object contains no data, even if shipment collection is correct. I believe, such a behavior does not depend on data passed as a parameter. Probably i've made something wrong with the streams. How to use them properly? How to generate csv file correctly using CsvHelper library?
I've found a solution. StreamWriter has to be flushed, after writing records, so now the function looks like:
public async Task<Report> GenerateReportAsync(ICollection<ShipmentEntity> shipmentEntities)
{
var shipment = shipmentEntities
.Select(s => (Shipment) s)
.ToList();
await using var memoryStream = new MemoryStream();
await using var streamWriter = new StreamWriter(memoryStream);
await using var csvWriter = new CsvWriter(streamWriter, CultureInfo.InvariantCulture);
csvWriter.Configuration.Delimiter = ";";
await csvWriter.WriteRecordsAsync(shipment);
await streamWriter.FlushAsync();
var report = new Report
{
Content = memoryStream.ToArray(),
Type = ReportConstants.CsvFileType,
Name = ReportConstants.CsvReportFileName
};
return report;
}
And it works properly :)

How to return a specified Json format in c#

Hi all I am trying to build a quiz application using angular JS, I am having two tables Questions and Answers and the code is as follows
public class Question
{
public int QuestionID { get; set; }
public string QuestionName { get; set; }
public List<Options> Options = new List<Options>();
}
public class Options
{
public int AnswerId { get; set; }
public int QuestionID { get; set; }
public string Answer { get; set; }
public bool isAnswer { get; set; }
}
public static class QuizDetails
{
public static string GetQuiz()
{
Dictionary<int, List<Question>> displayQuestion = new Dictionary<int, List<Question>>();
//List<Quiz> quiz = new List<Quiz>();
//Options op1 = new Options();
dbDataContext db = new dbDataContext();
var v = (from op in db.QUESTIONs
join pg in db.ANSWERs on op.QUESTION_ID equals pg.QUESTION_ID
select new { Id = op.QUESTION_ID, Name = op.QUESTION_NAME, pg.ANSWER_ID, pg.QUESTION_ID, pg.ANSWER_DESCRIPTION, pg.CORRECT_ANSWER }).ToList();
return JsonConvert.SerializeObject(v);
}
}
This is my reference code for building the application
http://www.codeproject.com/Articles/860024/Quiz-Application-in-AngularJs, how can I return the JSON format as per the code written in the JS files can some one help me
Right now GetQuiz returns a string that represents an object. Your client doesn't really know what the string contains, it just handles it as a normal string.
You can either return it in another way, for example:
return new HttpResponseMessage
{
Content = new StringContent(
JsonConvert.SerializeObject(v),
System.Text.Encoding.UTF8,
"application/json")
};
If you want to keep returning it as a string you will have to manually deserialize it in the client:
var object = angular.fromJson(returnedData);

How to apply lazy loading to bing ListView in windows store app?

I am working on Sales App of Windows Store app. I want to apply lazy loading for my product module.
When Product page open it get product from backend and show in ListBox control.
It takes time everytime to load. I think main reason is when I check for the image exists on given url.
Here is my code and class:
private async Task getAllProductDetails()
{
var resultproductlist = await client.PostAsync(session.Values["URL"] + "/magemobpos/product/getProductList", contents);
if (resultproductlist.IsSuccessStatusCode)
{
string trys = resultproductlist.Content.ReadAsStringAsync().Result;
List<Productlistdata> objProducts = JsonConvert.DeserializeObject<ProductlistResponse>(trys).productlistdata;
Productlistdata Product;
//all product are in objProducts
foreach (var item in objProducts)
{
bool imageexist = false;
//check if image exist on given url or not
try
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(new Uri(item.image.ToString()));
using (var response = (HttpWebResponse)(await Task<WebResponse>.Factory.FromAsync(request.BeginGetResponse, request.EndGetResponse, null)))
{
int imagelength = Convert.ToInt32(response.ContentLength);
if (imagelength > 0)
imageexist = true;
else
imageexist = false;
}
}
catch (Exception)
{
imageexist = false;
}
//if image not exist, it get default image
if (item.image.ToString().ToLower().Equals("n/a") || imageexist == false)
{
item.image = "Images/NoDataImages/ico-no-orders.png";
}
Product = new Productlistdata()
{
image = item.image,
name = item.name,
price = item.price,
sku = item.sku,
type = item.type[0],
id = item.id
};
//add all product in lstProduct. lstProduct is ListBox Control
lstProduct.Items.Add(Product);
}
}
}
Class:
public class Productlistdata
{
public string id { get; set; }
public string sku { get; set; }
public string name { get; set; }
public string status { get; set; }
public string qty { get; set; }
public string price { get; set; }
public string image { get; set; }
public string type { get; set; }
public string full_productname { get; set; }
}
Can anybody suggest me how to apply lazy loading? I don't know exactly but I think it can apply to bind image once the list is loaded.
I know that you dint ask for it but I ll strongly suggest you to look into Bindings I believe it will help you a lot thinking what you are trying to build. So I ll start by changing some of your code using bindings and then go to the real solution.
Here is what you can try and do:
First remove this code:
bool imageexist = false;
//check if image exist on given url or not
try
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(new Uri(item.image.ToString()));
using (var response = (HttpWebResponse)(await Task<WebResponse>.Factory.FromAsync(request.BeginGetResponse, request.EndGetResponse, null)))
{
int imagelength = Convert.ToInt32(response.ContentLength);
if (imagelength > 0)
imageexist = true;
else
imageexist = false;
}
}
catch (Exception)
{
imageexist = false;
}
Second Step is to get rid of this code
//add all product in lstProduct. lstProduct is ListBox Control
lstProduct.Items.Add(Product);
Now add on top of you page.xaml.cs an ObservableCollection
private ObservableCollection<Productlistdata> productlist = new ObservableCollection<Productlistdata>();
public ObservableCollection<Productlistdata> Productlist
{
get { return productlist ?? (productlist= new ObservableCollection<Productlistdata>()); }
set { productlist= value; }
}
Now you either bind that list in the list box like this
<ListBox ItemsSource="{Binding Productlist}"/>
or In the Contractor of your page do
lstProduct.ItemsSource = Productlist;
That way Productlist is binded to your ListBox and when you add or remove items will it will be updated automatically.
Now you can skip all the above but I suggest you to look into Bindings it powerfull and will solve many of your problems when you get the idea of they work.
Now we will add the first code we removed in your ProductListdata
public class Productlistdata
{
public string id { get; set; }
public string sku { get; set; }
public string name { get; set; }
public string status { get; set; }
public string qty { get; set; }
public string price { get; set; }
public string image { get; set; }
public string type { get; set; }
public string full_productname { get; set; }
public async void CheckImage()
{
bool imageexist = false;
try
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(new Uri(image));
using (var response = (HttpWebResponse)(await Task<WebResponse>.Factory.FromAsync(request.BeginGetResponse, request.EndGetResponse, null)))
{
int imagelength = Convert.ToInt32(response.ContentLength);
if (imagelength > 0)
imageexist = true;
else
imageexist = false;
}
}
catch (Exception)
{
imageexist = false;
}
if (!imageexist)
{
image = "Images/NoDataImages/ico-no-orders.png";
}
}
}
And populate your List
private async Task getAllProductDetails()
{
var resultproductlist = await client.PostAsync(session.Values["URL"] + "/magemobpos/product/getProductList", contents);
if (resultproductlist.IsSuccessStatusCode)
{
string trys = resultproductlist.Content.ReadAsStringAsync().Result;
List<Productlistdata> objProducts = JsonConvert.DeserializeObject<ProductlistResponse>(trys).productlistdata;
//all product are in objProducts
foreach (var item in objProducts)
{
Productlistdata Product = new Productlistdata()
{
image = item.image,
name = item.name,
price = item.price,
sku = item.sku,
type = item.type[0],
id = item.id
};
Product.CheckImage();
Productlist.Add(Product);
}
}
}
Product.CheckImage(); will not be awaited. So the Items in the list will load really fast because nothing is awaited in the foreach loop. Product.CheckImage(); will run on another thread at later time.
Finally because image might change after the data is loaded on the ListBoxa(when image wasnt fount) you will have to Notify the UI that a property has changed. To do that you will have to use INotifyPropertyChanged. You can take a look in an other answer of mine how to do that here
I would suggest changing your queries,
firstly instead of getAllProductDetails do getAllProductID
so where you have
var resultproductlist = await client.PostAsync(session.Values["URL"] + "/magemobpos/product/getProductList", contents);
if (resultproductlist.IsSuccessStatusCode)
{
string trys = resultproductlist.Content.ReadAsStringAsync().Result;
List<Productlistdata> objProducts = JsonConvert.DeserializeObject<ProductlistResponse>(trys).productlistdata;
Productlistdata Product;
you would do
var resultproductlist = await client.PostAsync(session.Values["URL"] + "/magemobpos/product/getProductID", contents);
if (resultproductlist.IsSuccessStatusCode)
{
string trys = resultproductlist.Content.ReadAsStringAsync().Result;
List<int> objProducts = JsonConvert.DeserializeObject<ProductlistResponse>(trys).productlistdata;
LazyProductlistdata Product;
secondly create a wrapper
public LazyProductlistdata
{
public string id { get; set; }
private Lazy<Productlistdata> data = new Lazy<Productlistdata>(()=>Productlistdata.CreateFromID(id));
public Productlistdata Data
{
get{return data.Value;}
}
}
expand this so the wrapper contains information required for sorting
finally alter the constructor or create a factory for Productlistdata so that it obtains the individual record from the source
public class Productlistdata
{
public static Productlistdata CreateFromID(int id)
{
//Return single Productlistdata from webservice
}
}
NOTE: lazy loading will increase the overall load time, the advantange is that instead of it being 1 huge block of time its several smaller ones
I would suggest using Converter to supply placeholder see here.
You can also decorate Image.Source binding with IsAsync = True - so that main thread would not be blocked
You can use ImageFailed event to assign image placeholder
foreach (var item in objProducts)
{
var bitmap = new BitmapImage();
bitmap.ImageFailed += (s, e) => bitmap.UriSource = defaultImageUri;
bitmap.UriSource = new Uri(item.image);
item.Add(bitmap);
//set decodepixelwidth and dicodepixelheight correctly to avoid outofmemory exception
}

assigning value to complex variable in controller, i get Object reference not set to an instance of an object

public class kingdomAddModel
{
public string title { get; set; }
public string details { get; set; }
//public HttpPostedFileBase fileUpload { get; set; }
//public string retrieveFile { get; set; }
public FileAttr files { get; set; }
}
public class FileAttr
{
public HttpPostedFileBase fileUpload { get; set; }
public string retrieveFile { get; set; }
}
var getDailyDevotions = db.DailyDevotions.Select(d => new { title = d.DevotionsTitle, details = d.DevotionsDetails, retriveFileAudio = d.VoiceNotes });
List<kingdomAddModel> listdevotions = new List<kingdomAddModel>();
foreach (var getDevotions in getDailyDevotions)
{
kingdomlist = new kingdomAddModel();
kingdomlist.title = getDevotions.title;
kingdomlist.details = getDevotions.details;
fileattr = new FileAttr();
fileattr.retrieveFile = getDevotions.retriveFileAudio;
kingdomlist.files.retrieveFile = fileattr.retrieveFile; //erros appears here!
}
The line line kingdomlist.files.retrieveFile throws the exception, tried googling but I dont get simular problem. I just want to assign the value and will pull on my view.
Do not access properties of FileAttr directly, only use files with the instance of kingdomAddModel. Don't mixup them
Replace
foreach (var getDevotions in getDailyDevotions)
{
kingdomlist = new kingdomAddModel();
kingdomlist.title = getDevotions.title;
kingdomlist.details = getDevotions.details;
fileattr = new FileAttr();
fileattr.retrieveFile = getDevotions.retriveFileAudio;
kingdomlist.files.retrieveFile = fileattr.retrieveFile; //erros appears here!
}
with
foreach (var getDevotions in getDailyDevotions)
{
kingdomlist = new kingdomAddModel
{
title = getDevotions.title,
details = getDevotions.details,
files = new FileAttr
{
retrieveFile = getDevotions.retriveFileAudio,
//fileUpload = some value here
}
};
listdevotions.Add(kingdomlist);
}
OR use Linq
listdevotions = (from getDevotions in getDailyDevotions
select new kingdomAddModel
{
title = getDevotions.title,
details = getDevotions.details,
files = new FileAttr
{
retrieveFile = getDevotions.retriveFileAudio,
//fileUpload = some value here
}
}).ToList();

How to Create multi level Json using Jobject in C#?

I want to create multi level Json, Using http://json2csharp.com/. I created classes. But not sure how to use it.
public class MassPay
{
public string legal_name { get; set; }
public string account_number { get; set; }
public string routing_number { get; set; }
public string amount { get; set; }
public string trans_type { get; set; }
public string account_class { get; set; }
public string account_type { get; set; }
public string status_url { get; set; }
public string supp_id { get; set; }
public string user_info { get; set; }
}
public class MassPayList
{
public string oauth_consumer_key { get; set; }
public string bank_id { get; set; }
public string facilitator_fee { get; set; }
public IList<MassPay> mass_pays { get; set; }
}
These are my classes and this is Json Format i want to create...
there are extra elements...
{
"oauth_consumer_key":"some_oauth_token",
"mass_pays":[
{"legal_name":"SomePerson1",
"account_number":"888888888",
"routing_number":"222222222",
"amount":"10.33",
"trans_type":"0",
"account_class":"1",
"account_type":"2"
},
{"legal_name":"SomePerson2",
"account_number":"888888888",
"routing_number":"222222222",
"amount":"10.33",
"trans_type":"0",
"account_class":"1",
"account_type":"1"}
]
}
So far i have come up with below code..I am using JObject, and all others wer single level so it was pretty easy. but when it comes to two or three level its difficult.
public JObject AddMassPayRequest(MassPayList lMassPayList, MassPay lMassPay)
{
JObject pin = new JObject(
new JProperty("legal_name", lMassPay.legal_name),
new JProperty("account_number", lMassPay.account_number),
new JProperty("routing_number", lMassPay.routing_number),
new JProperty("amount", lMassPay.amount),
new JProperty("trans_type", lMassPay.trans_type),
new JProperty("account_class", lMassPay.account_class),
new JProperty("account_type", lMassPay.account_type),
new JProperty("status_url", lMassPay.status_url),
new JProperty("supp_id", lMassPay.supp_id),
new JProperty("status_url", lMassPay.status_url),
new JProperty("user_info", lMassPay.user_info)
);
return pin;
}
public JObject AddMassPayRequestList(MassPayList lMassPayList, MassPay lMassPay)
{
JObject pin = new JObject(
new JProperty("mass_pays", lMassPayList.mass_pays),
new JProperty("bank_id", lMassPayList.bank_id),
new JProperty("facilitator_fee", lMassPayList.facilitator_fee),
new JProperty("oauth_consumer_key", lMassPayList.oauth_consumer_key)
);
return pin;
}
Can some one help me how to do this..?
if you're using ASP.NET MVC you just need to use the Json response action using your existing classes.
You could simply do something like this in a controller:
return Json(new { PoId = newPoId, Success = true });
or an actual concrete model class:
var _AddMassPayRequestList = new AddMassPayRequestList();
...
returning a populated instance of your AddMassPayRequestList class:
return Json(_AddMassPayRequestList);
So finally I got this answer, Its simple structure. Using this u can create any type of Json... It doesnt have to follow same structure..
The logic behind this is add things you want at start, create class and inside that properties you want to add into json. SO while passign just add for loop and pass Object to the list.. It will loop through and create JSon for You..
If you have any doubts, let me know happy to help you
public String ToJSONRepresentation(List<MassPay> lMassPay)
{
StringBuilder sb = new StringBuilder();
JsonWriter jw = new JsonTextWriter(new StringWriter(sb));
jw.Formatting = Formatting.Indented;
jw.WriteStartObject();
jw.WritePropertyName("oauth_consumer_key");
jw.WriteValue("asdasdsadasdas");
jw.WritePropertyName("mass_pays");
jw.WriteStartArray();
int i;
i = 0;
for (i = 0; i < lMassPay.Count; i++)
{
jw.WriteStartObject();
jw.WritePropertyName("legal_name");
jw.WriteValue(lMassPay[i].legal_name);
jw.WritePropertyName("account_number");
jw.WriteValue(lMassPay[i].account_number);
jw.WritePropertyName("routing_number");
jw.WriteValue(lMassPay[i].routing_number);
jw.WritePropertyName("amount");
jw.WriteValue(lMassPay[i].amount);
jw.WritePropertyName("trans_type");
jw.WriteValue(lMassPay[i].trans_type);
jw.WritePropertyName("account_class");
jw.WriteValue(lMassPay[i].account_class);
jw.WritePropertyName("account_type");
jw.WriteValue(lMassPay[i].account_type);
jw.WritePropertyName("status_url");
jw.WriteValue(lMassPay[i].status_url);
jw.WritePropertyName("supp_id");
jw.WriteValue(lMassPay[i].supp_id);
jw.WriteEndObject();
}
jw.WriteEndArray();
jw.WriteEndObject();
return sb.ToString();
}

Categories

Resources