Get message from FieldDescriptor in protobuf - c#

In protobuf (C#) I want to print all fields inside different messages and submessages. How can I get message type and send to function again (recursive walking to lowest child)? More specific: What I must do, that fieldDescriptor is send like a message? I search solution, which is change "???".
private void PrintAllReportableFieldsinMessage(Google.Protobuf.IMessage message)
{
foreach (var fieldDescriptor in message.Descriptor.Fields.InFieldNumberOrder())
{
if (fieldDescriptor.FieldType == Google.Protobuf.Reflection.FieldType.Message)
{
PrintAllReportableFieldsinMessage(???); // What can I send here?
}
else
{
Google.Protobuf.Reflection.FieldOptions options = fieldDescriptor.GetOptions();
if (options != null && options.GetExtension(HelloworldExtensions.Reportable))
{
var fieldValue = fieldDescriptor.Accessor.GetValue(message);
var fieldName = fieldDescriptor.Name;
Dispatcher.Invoke(() =>
{
lReadableResult.Content += fieldName + ":" + fieldValue + "|";
});
}
}
}
}

I found a solition. HasValue return false, if any values inside submessage are not set. Then I must create a new Imessage which have all default values. So then this code works for printing all field names in all messages and submessages.
private void PrintAllReportableFieldsinMessage(Google.Protobuf.IMessage message)
{
foreach (var fieldDescriptor in message.Descriptor.Fields.InFieldNumberOrder())
{
if (fieldDescriptor.FieldType == Google.Protobuf.Reflection.FieldType.Message)
{
if (fieldDescriptor.Accessor.HasValue(message))
{
IMessage submessage = fieldDescriptor.Accessor.GetValue(message) as IMessage;
PrintAllReportableFieldsinMessage(submessage);
}
else {
IMessage cleanSubmessage = fieldDescriptor.MessageType.Parser.ParseFrom(ByteString.Empty);
PrintAllReportableFieldsinMessage(cleanSubmessage);
}
}
else
{
Google.Protobuf.Reflection.FieldOptions options = fieldDescriptor.GetOptions();
if (options != null && options.GetExtension(HelloworldExtensions.Reportable))
{
var fieldValue = fieldDescriptor.Accessor.GetValue(message);
var fieldName = fieldDescriptor.Name;
Dispatcher.Invoke(() =>
{
lReadableResult.Content += fieldName + ":" + fieldValue + "|";
});
}
}
}
}

Related

Custom Function to detect return type(SOAP,XML,FLAT FILE in custom format) and apply custom logic C#

I need to write a function which applies custom logic to retrieve data from the return type there are 3 type of return types I get
SOAP,
XML,
FLAT FILE (eg. Staring with ABC),
FLAT FILE (eg. Staring with XYZ).
For now I am trying to get the start string and then detect the return type. I need a better way to do it as I will need to check other flat file formats in the future.
As of now i am putting it in a IF else condition.
`
string body = GetMessage();
string startStr = body.Substring(0, Math.Min(body.Length, 5)).ToUpper();
XDocument xml = null;
if (!string.IsNullOrEmpty(body))
{
try
{
if (startStr == "<SOAP")
{
xml = XDocument.Parse(body);
string senderInfo = string.Empty;
string receiverInfo = string.Empty;
XElement senderQ = xml.Root.Descendants().Where(x => x.Name.LocalName == "_SENDERQ_").FirstOrDefault();
XElement receiverQ= xml.Root.Descendants().Where(x => x.Name.LocalName == "_RECEIVERQ").FirstOrDefault();
XElement senderId = xml.Root.Descendants().Where(x => x.Name.LocalName == "_SENDERID_").FirstOrDefault();
XElement receiverId = xml.Root.Descendants().Where(x => x.Name.LocalName == "_RECEIVERID_").FirstOrDefault();
if (senderId != null)
{
senderInfo = senderId.Value.Trim();
}
if (senderQ != null)
{
senderInfo += " : " + senderQ.Value.Trim();
}
if (receiverId != null)
{
receiverInfo = receiverId.Value.Trim();
}
if (receiverQ != null)
{
receiverInfo += " : " + receiver.Value.Trim();
}
if (!String.IsNullOrEmpty(senderInfo) && !String.IsNullOrEmpty(receiverInfo))
{
idList.Add(senderInfo);
idList.Add(receiverInfo);
}
return idList;
}
else if (startStr == "<?XML")
{
xml = XDocument.Parse(body);
XElement xbody = xml.Descendants("message").Elements("body").FirstOrDefault();
if (xbody != null )
{
string mbody = xbody.Value;
if (!string.IsNullOrEmpty(xbody.Value))
{
idList = GetSenderReceiverID(xbody.Value);
}
}
}
else if (startStr == "ABC")
{
string receiverId = msgbody.Substring(msgbody.IndexOf("RID") + 5, 65);
if (!string.IsNullOrEmpty(receiverId))
{
idList.Add(receiverId.Trim() + " : N/A");
}
string senderId = msgbody.Substring(msgbody.IndexOf("SID") + 5, 65);
if (!string.IsNullOrEmpty(senderId))
{
idList.Add(senderId.Trim() + " : N/A");
}
}
else
{
string IsPO = body.Substring(0, Math.Min(body.Length, 23)).ToUpper();
if (!string.IsNullOrEmpty(IsPO))
{
string trimmedBody =
if(IsPO == "|XYZ|")
{
idList = GetSenderReceiverID(xbody.Value);
}
}
}
}
catch (Exception ex) { }
}
`

How to handle New transaction is not allowed because there are other threads running in the session for multiple calls or to save as list of Entities

Hi I am using Entity Framework Code First, I have a collection of Entities that need to be saved, but I have my EF Repository created as below
public T Create(T item)
{
try
{
if (ufb != null && ufb.CurrentUser != null)
{
SetValue("CreatedByUserId", item, ufb.CurrentUser.Id);
SetValue("UpdatedByUserId", item, ufb.CurrentUser.Id);
}
SetValue("DateCreated", item, DateTime.Now);
SetValue("DateUpdated", item, DateTime.Now);
var newEntry = this.DbSet.Add(item);
this.Context.Database.Log = message => LogHandler.LogInfo(1111, message);
try
{
this.Context.SaveChanges();
}
catch (Exception ex)
{
LogHandler.LogInfo(2501, ex.Message);
}
BuildMetaData(item, true, true);
return newEntry;
}
catch (DbEntityValidationException dbEx)
{
// http://forums.asp.net/t/2014382.aspx?Validation+failed+for+one+or+more+entities+See+EntityValidationErrors+property+for+more+details+
string msg = string.Empty;
foreach (var validationErrors in dbEx.EntityValidationErrors)
{
foreach (var validationError in validationErrors.ValidationErrors)
{
msg += validationError.PropertyName;
msg += "---";
msg += validationError.ErrorMessage;
msg += "||";
}
}
throw new Exception("7777 CREATE EntityValidationErrors: " + msg);
}
}
My calling method is as below:
public List<VehicleInfo> Create(List<VehicleInfo> vehicleInfos, string Entity, int EntityId)
{
bool vehicleExists = false; List<VehicleInfo> newVehicleInfos = null;
if ((vehicleInfos != null) && (vehicleInfos.Count > 0))
{
newVehicleInfos = new List<VehicleInfo>();
foreach (VehicleInfo vehicleInfo in vehicleInfos)
{
vehicleExists = false;
if (vehicleInfo != null)
{
vehicleExists = this.VehicleExists(vehicleInfo.VehicleId, Entity, EntityId);
vehicleInfo.Entity = Entity;
vehicleInfo.EntityId = EntityId;
VehicleInfo v = this.UnitOfWork.VehicleInfoRepository.Create(vehicleInfo);
newVehicleInfos.Add(v);
}
}
}
return newVehicleInfos;
}
Hence when I am calling repositories create method for multiple times, its throwing me the above error, any help or suggestion would be very helpful, please thank you.
void BuildMetaDataNoThread(object item, bool active, bool isNew = false)
{
if (item.GetType() != typeof(JsonObject))
{
var dm = new DataAccessUnitOfWork(Constants.DefaultConnection);
var qtype = item.GetType();
if (qtype.BaseType.BaseType != null)
{
if ((isNew && qtype.BaseType.Name == typeof(ModelBase).Name) | qtype.BaseType.BaseType.Name == typeof(ModelBase).Name)
{
Thread.Sleep(500);
//collect data
var element = (ModelBase)item;
element.BuildMetaData(DataRequestType.CurrentItem);
var records = ModelBase.MetaData;
ModelBase.MetaData = new List<ModelRecord> { };
if (records == null) return;
foreach (ModelRecord r in records)
{
if (r!=null)
{
var jsr = new JavaScriptSerializer();
//object meta = r;
object rdata = r.Data;
var type = rdata.GetType();
var token = type.BaseType.Name;
List<string> include = r.Include;
// Cycle-through clieanup of models to be encoded into Json Data.
// this helper eliminates infinate relations by including records specified
// by a list of strings
if (include.Where(x => x.Contains("CreatedByUser")).Count() == 0)
include.Add("CreatedByUser");
if (include.Where(x => x.Contains("UpdatedByUser")).Count() == 0)
include.Add("UpdatedByUser");
var data = ClassCloner.CollectData(rdata, include);
List<string> tags = ClassCloner.CollectTags(data);
string _tags = "";
tags.ForEach((xtm) =>
{
_tags += xtm + ',';
});
var json = jsr.Serialize(data);
int id = 0;
//get identity
foreach (var prop in type.GetProperties())
{
if (id == 0)
{
foreach (var cp in prop.CustomAttributes)
{
if (cp.AttributeType.Name == "KeyAttribute")
{
var _id = ((Dictionary<string, object>)data)[prop.Name];
id = (int)_id;
break;
}
}
}
else { break; }
}
var query = dm.JsonObjectRepository.GetAll();
var key = "_" + token;
var _data = (Dictionary<string, object>)data;
var ExistingMetaData = (from x in query where x.SourceKey == key && x.SourceId == id select x).FirstOrDefault();
if (ExistingMetaData != null)
{
if (_data.ContainsKey("DateUpdated")) ExistingMetaData.Date = (DateTime)_data["DateUpdated"];
ExistingMetaData.SourceData = data;
ExistingMetaData.Encode();
ExistingMetaData.Active = active;
ExistingMetaData.SearchTags = _tags;
dm.JsonObjectRepository.Update(ExistingMetaData);
}
else
{
var newData = new JsonObject
{
Active = true,
Date = (DateTime)_data["DateUpdated"],
SourceData = data,
SourceId = id,
SourceKey = key,
SearchTags = _tags,
TargetKey = "GlobalSearchMetaData"
};
newData.Encode();
dm.JsonObjectRepository.Create(newData);
}
}
}
}
}
}
}
void BuildMetaData(object dataRecord, bool active, bool isNew)
{
new Thread((item) => { BuildMetaDataNoThread(item, active, isNew); }).Start(dataRecord);
}

How to use Reflection with Non-Generic Types

I've spent hours on here looking for an answer to my problem so I'm sorry if this is a duplicate query. If so, please point me in the right direction. If not, see below, I've been tasked with the following:
Create a function that can, dynamically, check the database to see if a value is present for a certain object.
Basically, the user clicks a button which moves an item to another Stage. The next stage may/may not have requirements before being able to enter that stage. If requirements are present, there are two data points sent to me:
ReflectionClass (string) [I will either use the DbSet string value OR the Class string value here]
ReflectionProperty (string)
With these two pieces of data I need to check the database (via DbSet preferably, using LINQ or Reflection).
The ReflectionClass variable can refer to one of 5 tables in the database. So, essentially, I need a way to say: db.[DbSet].Any(w=>w.ID == PipelineID && w.[ReflectionProperty] != null) or something like this...
I've tried using ExpressionTrees but I can't get the Func<T,bool> to work with a Type variable. See my code below, this will work, but I know there is a more efficient way to do this using Reflection, I just don't know how.
public async Task<Feedback> vStageReqFields(Guid NextStageID, Guid PipelineID)
{
Feedback f = new Feedback();
bool Valid = true;
string InvalidList = string.Empty;
List<Domain.Pipeline.Pipeline> pipelines = new List<Domain.Pipeline.Pipeline>();
List<Domain.Pipeline.Billing> billings = new List<Domain.Pipeline.Billing>();
try
{
//Get a list of Validations needed before advancing Stage...
var validations = db.PipelineStageRequiredFields.Any(a=>a.StageID == NextStageID) ? db.PipelineStageRequiredFields.Where(w=>w.StageID == NextStageID).ToList() : null;
//If Validations exist, start validatiing...
if(validations != null && validations.Any())
{
Type objectType = (from asm in AppDomain.CurrentDomain.GetAssemblies()
from type in asm.GetTypes()
where type.IsClass && type.FullName == "Domain.Pipeline.Pipeline" // static class to find Assembly info, all v.ReflectionClasses come from the same Assembly...
select type).SingleOrDefault();
foreach (var v in validations)
{
if(Utility.HasProperty(objectType, v.RefelectionProperty))//Check to see if ReflectionsClass has ReflectionProperty
{
//Switch Statement for Reflection Class to Check Property Value...
switch (v.RefelectionClass)
{
case "Domain.Pipeline.Pipeline":
pipelines = GetAllMembers(db, "Pipelines").OfType<Domain.Pipeline.Pipeline>().Where(w => w.ID == PipelineID).ToList(); //Get all Pipeline Objects...
if (pipelines.Any())
{
var model = pipelines.FirstOrDefault();
var value = model.GetType().GetProperty(v.RefelectionProperty).GetValue(model, null); //Check if Required ReflectionProperty has a value...
if (value == null)
{
Valid = false;
if (string.IsNullOrEmpty(InvalidList))
{
InvalidList = "The following fields are required: " + v.RefelectionProperty;
}
else
{
InvalidList = InvalidList + ", " + v.RefelectionProperty;
}
}
}
else
{
f.Success = false;
f.Type = FeedbackType.Error;
f.SuccessMsg = "Error: Could not find a Pipeline with this ID: '" + PipelineID.ToString() + "'";
}
break;
case "Domain.Pipeline.Billing":
billings = GetAllMembers(db, "Billings").OfType<Domain.Pipeline.Billing>().Where(w => w.PipelineID == PipelineID).OrderByDescending(o => o.EffectiveDate).ToList();
if (billings.Any())
{
var model = billings.FirstOrDefault();
var value = model.GetType().GetProperty(v.RefelectionProperty).GetValue(model, null);
if (value == null)
{
Valid = false;
if (string.IsNullOrEmpty(InvalidList))
{
InvalidList = "The following fields are required: " + v.RefelectionProperty;
}
else
{
InvalidList = InvalidList + ", " + v.RefelectionProperty;
}
}
}
else
{
f.Success = false;
f.Type = FeedbackType.Error;
f.SuccessMsg = "Error: Could not find a Pipeline with this ID: '" + PipelineID.ToString() + "'";
}
break;
default:
f.Success = false;
f.Type = FeedbackType.Error;
f.SuccessMsg = "Error: Could not find any Data in the " + v.RefelectionClass + " table for this Pipeline: '" + PipelineID.ToString() + "'";
break;
}
}
else
{
f.Success = false;
f.Type = FeedbackType.Error;
f.SuccessMsg = "The " + v.RefelectionClass + " does not have a Property of " + v.RefelectionProperty;
}
}
}
//No Validations Exist, User can proceed...
else
{
f.Success = true;
f.Type = FeedbackType.Success;
f.SuccessMsg = "Success! There are no required fields for the next stage.";
}
}
catch(Exception ex)
{
f.Success = false;
f.Type = FeedbackType.Error;
f.SuccessMsg = ITool.GetExceptionDetails(ex);
}
return f;
}
Here is the other function:
static IEnumerable GetAllMembers(DbContext DB, string dbSetName)
{
var model = DB.GetType().GetProperty(dbSetName);
return (IEnumerable)model.GetValue(DB);
}
Consider the following refactoring to remove repeated code and allow it to be more DRY (Don't Repeat Yourself).
public Feedback vStageReqFields(Guid NextStageID, Guid PipelineID) {
Feedback feedback = new Feedback();
List<string> required = new List<string>();
List<string> errors = new List<string>();
StringBuilder msg = new StringBuilder();
try {
//Get a list of Validations needed before advancing Stage...
var validations = db.PipelineStageRequiredFields.Where(w => w.StageID == NextStageID);
//If Validations exist, start validatiing...
if (validations.Any()) {
foreach (var field in validations) {
var className = field.RefelectionClass;
object model = null;
//Switch Statement for Reflection Class to Check Property Value...
switch (className) {
case "Domain.Pipeline.Pipeline":
model = db.Pipelines.FirstOrDefault(p => p.ID == PipelineID);
break;
case "Domain.Pipeline.Billing":
model = db.Billings.Where(w => w.PipelineID == PipelineID).OrderByDescending(o => o.EffectiveDate).FirstOrDefault();
break;
default:
errors.Add("Could not find any Data in the " + className + " table for this Pipeline: '" + PipelineID.ToString() + "'");
continue;
}
validate(field, PipelineID, model, required, errors);
}
if (required.Any()) {
msg.Append("The following fields are required: ")
.AppendLine(string.Join(", ", required));
}
if (errors.Any()) {
msg.AppendLine(string.Join(Environment.NewLine, errors));
}
}
if (msg.Length > 0) {
feedback.Success = false;
feedback.Type = FeedbackType.Error;
feedback.SuccessMsg = msg.ToString();
} else {
feedback.Success = true;
feedback.Type = FeedbackType.Success;
feedback.SuccessMsg = "Success! There are no required fields for the next stage.";
}
} catch (Exception ex) {
feedback.Success = false;
feedback.Type = FeedbackType.Error;
feedback.SuccessMsg = ITool.GetExceptionDetails(ex);
}
return feedback;
}
Use strong typing to find the desired object model.
The supporting validate method looks like this
private void validate(PipelineStageRequiredField field, Guid PipelineID, object model, List<string> required, List<string> errors) {
if (model != null) {
var propertyName = field.RefelectionProperty;
var objectType = model.GetType();
var propertyInfo = getProperty(objectType, propertyName);
if (propertyInfo != null) {
var isValidModel = buildRequiredFieldCheckDelegate(objectType, propertyInfo);
if (!(bool)isValidModel.DynamicInvoke(model)) {
required.Add(propertyInfo.Name);
}
} else {
errors.Add("The " + field.RefelectionClass + " does not have a Property of " + propertyName);
}
} else {
errors.Add("Error: Could not find a " + field.RefelectionClass + " with this Pipeline: '" + PipelineID.ToString() + "'");
}
}
private static PropertyInfo getProperty(Type type, string propertyName) {
return type.GetProperty(propertyName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase);
}
Where an expression can be built to check that the required field has a value
private Delegate buildRequiredFieldCheckDelegate(Type type, PropertyInfo propertyInfo) {
//Func<T, bool>
var delegateType = typeof(Func<,>).MakeGenericType(type, typeof(bool));
var prpertyDefaultValue = getDefaultValue(propertyInfo.PropertyType);
// p => p.Property != default(typeof(TProperty))
// p =>
var parameter = Expression.Parameter(type, "p");
// p => p.Property
var property = Expression.Property(parameter, propertyInfo);
// default(TProperty);
var defaultValue = Expression.Constant(prpertyDefaultValue);
// p => p.Property != default(TProperty)
var body = Expression.NotEqual(property, defaultValue);
// Func<T, bool> = T p => p.Property != default(TProperty)
var lambda = Expression.Lambda(delegateType, body, parameter);
return lambda.Compile();
}
private static object getDefaultValue(Type type) {
return type.IsValueType ? Activator.CreateInstance(type) : null;
}

Parsing out URLs in email messages

I'm having an issue in some of my code, i cannot seem to think of the best way to do this, all i want to do is extract a URL from a pop3 email message depending on if the domain is in the "to check" array, for example if "stackoverflow.com" is in the email message, i would extract all urls in the message body that contains "stackoverflow.com" in it, and just perform a quick WebClient() request with that url.
Code:
private void BgwEmails_DoWork_1(object sender, DoWorkEventArgs e)
{
try
{
bool finished = false;
Pop3Client pop3 = new Pop3Client();
if (pop3.Connected)
{
pop3.Disconnect();
}
pop3.Connect(txtBoxMailServer.Text, int.Parse(txtBoxPort.Text), chkSSL.Checked);
pop3.Authenticate(txtBoxUsername.Text, txtBoxPassword.Text, AuthenticationMethod.UsernameAndPassword);
int messageCount = pop3.GetMessageCount();
if (messageCount == 0)
{
return;
}
Helpers.ReturnMessage("[ " + messageCount + " ] Message(s) in your inbox.");
int count = 0;
for (int d = 1; d <= messageCount; d++)
{
bgwEmails.WorkerSupportsCancellation = true;
if (bgwEmails.CancellationPending)
{
e.Cancel = true;
Helpers.ReturnMessage($"Cancelling link activator ...");
return;
}
if (finished)
{
return;
}
OpenPop.Mime.Message message = null;
message = pop3.GetMessage(d);
if (null == message || null == message.MessagePart || null == message.MessagePart.MessageParts) {
continue;
}
string textFromMessage = null;
try
{
textFromMessage = message?.MessagePart?.MessageParts[0]?.GetBodyAsText();
} catch (Exception) {
continue;
}
MessagePart messagePart = message.MessagePart.MessageParts[0];
if (null == messagePart || null == messagePart.BodyEncoding || null == messagePart.Body || null == messagePart.BodyEncoding.GetString(messagePart.Body)) {
continue;
}
string linkToCheck;
using (var wc = new WebClient())
{
linkToCheck = wc.DownloadString("https://www.thesite.com/api.php?getActivationLinks=1");
}
var linksToClickArray = linkToCheck.Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
//Helpers.ReturnMessage(textFromMessage);
for (var i = 0; i < linksToClickArray.Length; i++)
{
var regex = new Regex(linksToClickArray[i], RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline);
var matches = regex.Matches(textFromMessage);
foreach (Match match in matches)
{
if (match.Success)
{
count++;
Invoke(new MethodInvoker(() => { listBoxEmailsClicked.Items.Add("Clicked: " + match.Value); }));
using (WebClient wc = new WebClient())
{
Helpers.ReturnMessage(match.Value);
wc.DownloadString(match.Value);
}
}
}
}
if (null != textFromMessage)
{
Invoke(new MethodInvoker(() => { txtStatusMessages.AppendText(textFromMessage); }));
}
}
Helpers.ReturnMessage($"Emails downloaded successfully! You clicked [ " + count + " ] activation links.");
} catch (Exception ex) {
Helpers.ReturnMessage($"POP3 Error: " + ex.Message + ".");
}
}
I do a request here: https://www.thesite.com/api.php?getActivationLinks=1 which contains a list of domains to check for in the messages, they just come back one line at a time like:
thesite1.com
thesite2.com
etc
The code works as far as connetcing and downloading, i just cannot seem to think of a way to parse of the urls only if it matches a domain in the target list, any help or advice would be appreciated.

System.OutOfMemoryException in C# when Generating huge amount of byte[] objects

I'm using this code to modify a pdf tmeplate to add specific details to it,
private static byte[] GeneratePdfFromPdfFile(byte[] file, string landingPage, string code)
{
try
{
using (var ms = new MemoryStream())
{
using (var reader = new PdfReader(file))
{
using (var stamper = new PdfStamper(reader, ms))
{
string _embeddedURL = "http://" + landingPage + "/Default.aspx?code=" + code + "&m=" + eventCode18;
PdfAction act = new PdfAction(_embeddedURL);
stamper.Writer.SetOpenAction(act);
stamper.Close();
reader.Close();
return ms.ToArray();
}
}
}
}
catch(Exception ex)
{
File.WriteAllText(HttpRuntime.AppDomainAppPath + #"AttachmentException.txt", ex.Message + ex.StackTrace);
return null;
}
}
this Method is being called from this Method:
public static byte[] GenerateAttachment(AttachmentExtenstion type, string Contents, string FileName, string code, string landingPage, bool zipped, byte[] File = null)
{
byte[] finalVal = null;
try
{
switch (type)
{
case AttachmentExtenstion.PDF:
finalVal = GeneratePdfFromPdfFile(File, landingPage, code);
break;
case AttachmentExtenstion.WordX:
case AttachmentExtenstion.Word:
finalVal = GenerateWordFromDocFile(File, code, landingPage);
break;
case AttachmentExtenstion.HTML:
finalVal = GenerateHtmlFile(Contents, code, landingPage);
break;
}
return zipped ? _getZippedFile(finalVal, FileName) : finalVal;
}
catch(Exception ex)
{
return null;
}
}
and here is the main caller,
foreach (var item in Recipients)
{
//...
//....
item.EmailAttachment = AttachmentGeneratorEngine.GenerateAttachment(_type, "", item.AttachmentName, item.CMPRCode, _cmpTmp.LandingDomain, _cmpTmp.AttachmentZip.Value, _cmpTmp.getFirstAttachment(item.Language, item.DefaultLanguage));
}
The AttachmentGeneratorEngine.GenerateAttachment method is being called approx. 4k times, because I'm adding a specific PDF file from a PDF template for every element in my List.
recently I started having this exception:
Exception of type 'System.OutOfMemoryException' was thrown. at System.IO.MemoryStream.ToArray()
I already implemented IDisposible in the classes and and I made sure that all of them are being released.
Note: it was running before very smoothely and also I double checked the system's resources - 9 GB is used out of 16 GB, so I had enough memory available.
==========================================
Update:
Here is the code that loops through the list
public static bool ProcessGroupLaunch(string groupCode, int customerId, string UilangCode)
{
CampaignGroup cmpGList = GetCampaignGroup(groupCode, customerId, UilangCode)[0];
_campaigns = GetCampaigns(groupCode, customerId);
List<CampaignRecipientLib> Recipients = GetGroupRcipientsToLaunch(cmpGList.ID, customerId);
try
{
foreach (var item in _campaigns)
item.Details = GetCampaignDetails(item.CampaignId.Value, UilangCode);
Stopwatch stopWatch = new Stopwatch();
#region single-threaded ForEach
foreach (var item in Recipients)
{
CampaignLib _cmpTmp = _campaigns.FirstOrDefault(x => x.CampaignId.Value == item.CampaignId);
bool IncludeAttachment = _cmpTmp.IncludeAttachment ?? false;
bool IncludeAttachmentDoubleBarrel = _cmpTmp.IncludeAttachmentDoubleBarrel ?? false;
if (IncludeAttachment)
{
if (_cmpTmp.AttachmentExtension.ToLower().Equals("doc") || (_cmpTmp.AttachmentExtension.ToLower().Equals("docx")))
_type = AttachmentGeneratorEngine.AttachmentExtenstion.Word;
else if (_cmpTmp.AttachmentExtension.ToLower().Equals("ppt") || (_cmpTmp.AttachmentExtension.ToLower().Equals("pptx")))
_type = AttachmentGeneratorEngine.AttachmentExtenstion.PowePoint;
else if (_cmpTmp.AttachmentExtension.ToLower().Equals("xls") || (_cmpTmp.AttachmentExtension.ToLower().Equals("xlsx")))
_type = AttachmentGeneratorEngine.AttachmentExtenstion.Excel;
else if (_cmpTmp.AttachmentExtension.ToLower().Equals("pdf"))
_type = AttachmentGeneratorEngine.AttachmentExtenstion.PDF;
else if (_cmpTmp.AttachmentExtension.ToLower().Equals("html"))
_type = AttachmentGeneratorEngine.AttachmentExtenstion.HTML;
}
//set "recpient" details
item.EmailFrom = _cmpTmp.EmailFromPrefix + "#" + _cmpTmp.EmailFromDomain;
item.EmailBody = GetChangedPlaceHolders((_cmpTmp.getBodybyLangCode(string.IsNullOrEmpty(item.Language) ? item.DefaultLanguage : item.Language, item.DefaultLanguage)), item.ID, _cmpTmp.CustomerId.Value, _cmpTmp.CampaignId.Value);
if (item.EmailBody.Contains("[T-LandingPageLink]"))
{
//..
}
if (item.EmailBody.Contains("[T-FeedbackLink]"))
{
//..
}
if (item.EmailBody.Contains("src=\".."))
{
//..
}
//set flags to be used by the SMTP Queue and Scheduler
item.ReadyTobeSent = true;
item.PickupReady = false;
//add attachment to the recipient, if any.
if (IncludeAttachment)
{
item.AttachmentName = _cmpTmp.getAttachmentSubjectbyLangCode(string.IsNullOrEmpty(item.Language) ? item.DefaultLanguage : item.Language, item.DefaultLanguage) + "." + _cmpTmp.AttachmentExtension.ToLower();
try
{
if (_type == AttachmentGeneratorEngine.AttachmentExtenstion.PDF || _type == AttachmentGeneratorEngine.AttachmentExtenstion.WordX || _type == AttachmentGeneratorEngine.AttachmentExtenstion.Word)
item.EmailAttachment = AttachmentGeneratorEngine.GenerateAttachment(_type, "", item.AttachmentName, item.CMPRCode, _cmpTmp.LandingDomain, _cmpTmp.AttachmentZip.Value, _cmpTmp.getFirstAttachment(item.Language, item.DefaultLanguage));
else item.EmailAttachment = AttachmentGeneratorEngine.GenerateAttachment(_type, value, item.AttachmentName, item.CMPRCode, _cmpTmp.LandingDomain, _cmpTmp.AttachmentZip.Value);
item.AttachmentName = _cmpTmp.AttachmentZip.Value ? (_cmpTmp.getAttachmentSubjectbyLangCode(string.IsNullOrEmpty(item.Language) ? item.DefaultLanguage : item.Language, item.DefaultLanguage) + ".zip") :
_cmpTmp.getAttachmentSubjectbyLangCode(string.IsNullOrEmpty(item.Language) ? item.DefaultLanguage : item.Language, item.DefaultLanguage) + "." + _cmpTmp.AttachmentExtension.ToLower();
}
catch (Exception ex)
{
}
}
else
{
item.EmailAttachment = null;
item.AttachmentName = null;
}
}
#endregion
stopWatch.Stop();
bool res = WriteCampaignRecipientsLaunch(ref Recipients);
return res;
}
catch (Exception ex)
{
Recipients.ForEach(i => i.Dispose());
cmpGList.Dispose();
Recipients = null;
cmpGList = null;
return false;
}
finally
{
Recipients.ForEach(i => i.Dispose());
cmpGList.Dispose();
Recipients = null;
cmpGList = null;
}
}

Categories

Resources