ICalendar (ICS) - only VEVENT components works good with outlook/googleCalendar - c#

I've got some problems with generating Icalendar files (*.ICS)
Im using library Ical.NET and c# language.
Code is very simple, for example this is VEVENT:
public override void HandleComponent(Ical.Net.Calendar root, CalendarData data)
{
var icalEvent = new Ical.Net.Event();
icalEvent.Start = new CalDateTime(data.Poczatek);
icalEvent.End = new CalDateTime(data.Koniec);
icalEvent.Location = data.Lokalizacja;
icalEvent.Description = data.Opis;
icalEvent.Summary = data.Nazwa;
root.Events.Add(icalEvent);
}
VJOURNEY and VTODO have very similar code <-- firstly i'm creating component, and then add it to calendar object.
Then i have generated file from this code:
var serializer = new CalendarSerializer(calendar);
var icsContent = serializer.SerializeToString();
return icsContent;
and structure of ics files looks like:
BEGIN:VCALENDAR
PRODID:-//github.com/rianjs/ical.net//NONSGML ical.net 2.2//EN
VERSION:2.0
BEGIN:VJOURNAL
ATTENDEE;CN=a;RSVP=TRUE;ROLE=REQ-PARTICIPANT:mailto:a#wp.pl
ATTENDEE;CN=a2;RSVP=TRUE;ROLE=REQ-PARTICIPANT:mailto:a2#wp.pl
DESCRIPTION:trele morele
DTSTAMP:20180913T072413Z
DTSTART:20180912T130700
ORGANIZER;CN=Administrator:mailto:Administrator#wp.pl
SEQUENCE:1
SUMMARY:qwerty22
UID:97032fa5-f554-4f10-9c4d-4fdda38148c7
END:VJOURNAL
END:VCALENDAR
just like specification says: https://www.kanzaki.com/docs/ical/vjournal.html
Problem:
Both Outlook 2016, and GoogleCalender handle properly only with VEVENT components on ICalendar file. When i import VJOURNAL or VTODO in GoogleCalendar it responds that he doesn't se any event...
Am i doing something wrong?
I also paste code where i create VJOURNAL
public class CalendarJournalComponent : CalendarComponents
{
public override CalendarComponentType SupportedComponent => CalendarComponentType.Journal;
public override void HandleComponent(Ical.Net.Calendar root, CalendarData data)
{
var journal = new Journal();
journal.Start = new CalDateTime(data.Poczatek);
journal.Description = data.Opis;
journal.Summary = data.Nazwa;
if (data.Prowadzacy.Any())
{
var prowadzacy = data.Prowadzacy.FirstOrDefault();
journal.Organizer = new Organizer() { CommonName = prowadzacy.Value, Value = emailUri(prowadzacy.Key)};
}
journal.Attendees = new List<IAttendee>();
foreach(var uczesnik in data.Uczestnicy)
{
journal.Attendees.Add(new Attendee() { CommonName = uczesnik.Value, Rsvp = true, Value = emailUri(uczesnik.Key), Role = "REQ-PARTICIPANT" });
}
root.Journals.Add(journal);
}
private Func<string, Uri> emailUri = x => new Uri(String.Format("mailto:{0}", x));
}
and VTODO compoment:
public class CalendarTodoComponent : CalendarComponents
{
public override CalendarComponentType SupportedComponent => CalendarComponentType.ToDo;
public override void HandleComponent(Ical.Net.Calendar root, CalendarData data)
{
var todo = new Todo();
todo.Start = new CalDateTime(data.Poczatek);
todo.Description = data.Opis;
todo.Summary = data.Nazwa;
todo.Location = data.Lokalizacja;
root.Todos.Add(todo);
}
}

Your code is most likely fine. But you need to ask yourself what you really expect to do by trying to import those VJOURNAL and VTODO in Google Calendar ?
As of today, Google Calendar really only support events/meetings:
It does not support VJOURNAL. As a matter of fact, there are really few software which do support VJOURNAL. From its definition (https://www.rfc-editor.org/rfc/rfc5545#section-3.6.3) you will see that it could be seen as the ancestor of a blog entry.
It does not support VTODO either. The closest you could find would be in Gmail which has a notion of Tasks list.

Related

How to change a ClassificationFormatDefinition

My Visual Studio extension (VSIX) is derived from the Ook Language Example (found here). Basically, I have the following ClassificationFormatDefinition with a function loadSavedColor that loads the color the user has configured. Everything works fine.
[Name("some_unique_name")]
internal sealed class OokE : ClassificationFormatDefinition
{
public OokE()
{
DisplayName = "ook!"; //human readable version of the name
ForegroundColor = loadSavedColor();
}
}
Question: After the user has configured a new color, I like to invalidate the existing instance of class OokE or change the existing instances and set ForegroundColor. But whatever I do the syntax color is not updated.
I've tried:
Get a reference to class OokE and update ForegroundColor.
Invalidate the corresponding ClassificationTypeDefinition:
[Export(typeof(ClassificationTypeDefinition))]
[Name("ook!")]
internal static ClassificationTypeDefinition ookExclamation = null;
After hours of sifting through code I could create something that works. The following method UpdateFont called with colorKeyName equal to "some_unique_name" does the trick. I hope it is useful for someone.
private void UpdateFont(string colorKeyName, Color c)
{
var guid2 = Guid.Parse("{A27B4E24-A735-4d1d-B8E7-9716E1E3D8E0}");
var flags = __FCSTORAGEFLAGS.FCSF_LOADDEFAULTS | __FCSTORAGEFLAGS.FCSF_PROPAGATECHANGES;
var store = GetService(typeof(SVsFontAndColorStorage)) as IVsFontAndColorStorage;
if (store.OpenCategory(ref guid2, (uint)flags) != VSConstants.S_OK) return;
store.SetItem(colorKeyName, new[]{ new ColorableItemInfo
{
bForegroundValid = 1,
crForeground = (uint)ColorTranslator.ToWin32(c)
}});
store.CloseCategory();
}
After setting the new color, you will need to clear the cache with the following code:
IVsFontAndColorCacheManager cacheManager = this.GetService(typeof(SVsFontAndColorCacheManager)) as IVsFontAndColorCacheManager;
cacheManager.ClearAllCaches();
var guid = new Guid("00000000-0000-0000-0000-000000000000");
cacheManager.RefreshCache(ref guid);
guid = new Guid("{A27B4E24-A735-4d1d-B8E7-9716E1E3D8E0}"); // Text editor category

Sabre Web Services .NET API Examples that aren't MVC?

This is pretty general, but I'm having a hell of a time figuring out how to consume some of the more complicated Sabre APIs.
I have built working .NET proxy classes in C# using the WSDL for the basic APIs (CreateSession, CloseSession) but for the more complicated APIs I have a really hard time parsing out the complicated XML schema to figure out which methods to call in my program.
Are there any other .NET resources/examples out there that aren't wrapped up in MVC like the code example that Sabre posted on GitHub?
I'm trying to figure out how to use APIs like OTA_AirPriceLLSRQ and TravelItineraryReadRQ.
Thanks in advance for any help!
As I mentioned on the comments, you should not focus on the actual MVC wrapping, as you'll be mainly putting stuff in the Model, or actually you'll put this somewhere else and consume it in the model.
Anyway, just for you to have as example, here's a VERY generic BFM (BargianFinderMax) class. With this approach it's required to create an instance, and after calling the Execute method it stores the response in the instance.
I hope it helps.
using BargainFinderMaxRQv310Srvc;
using System;
using System.IO;
namespace ServicesMethods
{
public class BFM_v310
{
private BargainFinderMaxService service;
private OTA_AirLowFareSearchRQ request;
public OTA_AirLowFareSearchRS response;
public BFM_v310(string token, string pcc, string convId, string endpoint)
{
//MessageHeader
MessageHeader mHeader = new MessageHeader();
PartyId[] pId = { new PartyId() };
pId[0].Value = "SWS";
From from = new From();
from.PartyId = pId;
To to = new To();
to.PartyId = pId;
mHeader.Action = "BargainFinderMaxRQ";
mHeader.Service = new Service()
{
Value = mHeader.Action
};
mHeader.ConversationId = convId;
mHeader.CPAId = pcc;
mHeader.From = from;
mHeader.To = to;
mHeader.MessageData = new MessageData()
{
Timestamp = DateTime.UtcNow.ToString()
};
//Security
Security security = new Security();
security.BinarySecurityToken = token;
//Service
service = new BargainFinderMaxService();
service.MessageHeaderValue = mHeader;
service.SecurityValue = security;
service.SoapVersion = System.Web.Services.Protocols.SoapProtocolVersion.Soap11;
service.Url = endpoint;
createRequest(pcc);
}
private void createRequest(string pcc)
{
request = new BargainFinderMaxRQv310Srvc.OTA_AirLowFareSearchRQ();
request.AvailableFlightsOnly = true;
request.Version = "3.1.0";
request.POS = new SourceType[1];
SourceType source = new SourceType();
source.PseudoCityCode = pcc;
source.RequestorID = new UniqueID_Type();
source.RequestorID.ID = "1";
source.RequestorID.Type = "1";
source.RequestorID.CompanyName = new CompanyNameType();
source.RequestorID.CompanyName.Code = "TN";
source.RequestorID.CompanyName.CodeContext = "Context";
request.POS[0] = source;
OTA_AirLowFareSearchRQOriginDestinationInformation originDestination = new OTA_AirLowFareSearchRQOriginDestinationInformation();
originDestination.OriginLocation = new OriginDestinationInformationTypeOriginLocation();
originDestination.OriginLocation.LocationCode = "BCN";
originDestination.DestinationLocation = new OriginDestinationInformationTypeDestinationLocation();
originDestination.DestinationLocation.LocationCode = "MAD";
originDestination.ItemElementName = ItemChoiceType.DepartureDateTime;
originDestination.Item = "2017-09-10T12:00:00";
originDestination.RPH = "1";
request.OriginDestinationInformation = new OTA_AirLowFareSearchRQOriginDestinationInformation[1] { originDestination };
request.TravelerInfoSummary = new TravelerInfoSummaryType()
{
AirTravelerAvail = new TravelerInformationType[1]
};
request.TravelerInfoSummary.AirTravelerAvail[0] = new TravelerInformationType()
{
PassengerTypeQuantity = new PassengerTypeQuantityType[1]
};
PassengerTypeQuantityType passenger = new PassengerTypeQuantityType()
{
Quantity = "1",
Code = "ADT"
};
request.TravelerInfoSummary.AirTravelerAvail[0].PassengerTypeQuantity[0] = passenger;
request.TravelerInfoSummary.PriceRequestInformation = new PriceRequestInformationType();
request.TravelerInfoSummary.PriceRequestInformation.CurrencyCode = "USD";
//PriceRequestInformationTypeNegotiatedFareCode nego = new PriceRequestInformationTypeNegotiatedFareCode();
//nego.Code = "ABC";
//request.TravelerInfoSummary.PriceRequestInformation.Items = new object[1] { nego };
request.TPA_Extensions = new OTA_AirLowFareSearchRQTPA_Extensions();
request.TPA_Extensions.IntelliSellTransaction = new TransactionType();
request.TPA_Extensions.IntelliSellTransaction.RequestType = new TransactionTypeRequestType();
request.TPA_Extensions.IntelliSellTransaction.RequestType.Name = "50ITIN";
}
public bool Execute()
{
response = service.BargainFinderMaxRQ(request);
return response.PricedItinCount > 0;
}
}
}
My advice is you should add separate models which are built based on Sabre models, and which flatten the whole structure.
For example, TravelItineraryReadRS is a quite complicated document. Using it properties in your program is a real "pain", because every time you need to remember the whole path that leads to to specific information (like, "what is passenger type for PersonName of NameNumber 01.01?").
I suggest you have dedicated model (let's name it Reservation), which have all information that you will need later in your application, extracted from TravelItineraryReadRs.
In order to achieve this you need a dedicated converter which will make convert TravelItineraryReadRs model into Reservation model. Now, inside Reservation model you could have list of Passenger models, which have in on place all important information (NameNumber, PassengerType, SSR codes, etc).
This improves readability and as a bonus you decouple your application from Sabre (imagine, one day someone asks "can we switch from Sabre to Amadeus?" - if you use dedicated models the answer is "yes". If you don't have, then the answer is "probably yes, but it will take 6-9 months).

Blank PDF being generated from ActiveReports/WebAPI

On a project I am working on, I'm building a feature that lets users generate a report - in my case, it will go on an envelope - on-demand from information stored in our database. The problem I'm trying to solve, is that a blank PDF is being generated.
I've tried some sanity checks. First I set a breakpoint in Visual Studio and ensured that the models being passed to the report had fixed data; the reports were blank. Next, I tried including a static label that's not tied to any data, to determine if it's a report data-binding issue - the static label is not appearing in the generated report either.
More stymying, is that I've used similar code in the past without issue. I have no idea why a blank PDF file would be generated in this case.
I've read the 'Similar Questions' provided by StackOverflow, specifically this question from one year ago, but it had no answers, and thus nothing to learn from it. I've also tried the requisite Google searches, but found nothing relevant.
The only thing I cannot provide is the actual ActiveReport itself. I've checked this for Silly Programmer Errors™ like having everything hidden, or transparent labels, or similar silly things. Unfortunately, I've made no such errors.
Report Code:
public partial class EnvelopeReport : SectionReport
{
public EnvelopeReport()
{
InitializeComponent();
}
internal void RunReport(IEnumerable<PrintedAddress> model)
{
if (model != null)
{
DataSource = model;
}
Run();
}
private void OnReportStart(object sender, EventArgs e)
{
Document.Printer.PrinterName = string.Empty;
PageSettings.PaperKind = PaperKind.Number10Envelope;
PageSettings.Margins.Top = 0.25f;
PageSettings.Margins.Left = 0.5f;
PageSettings.Margins.Right = 0.5f;
PageSettings.Margins.Bottom = 0.25f;
}
}
Web API Controller Code:
[HttpGet]
public HttpResponseMessage EnvelopeReport(int addressId, string attentionTo, bool isConfidential)
{
Address address = AddressRepository.GetAddress(addressId, true);
List<PrintedAddress> models = new List<PrintedAddress>
{
new PrintedAddress(address, attentionTo, isConfidential)
};
var report = new EnvelopeReport();
report.RunReport(models);
var pdfExporter = new ActiveReportsPdfExporter();
var reportBytes = pdfExporter.ExportPdf(report);
var response = Request.CreateResponse(HttpStatusCode.OK);
response.Content = new ByteArrayContent(reportBytes, 0, reportBytes.Length);
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
FileName = "Envelope Report.pdf"
};
return response;
}
PDF Exporter:
public class ActiveReportsPdfExporter
{
private readonly PdfExport _pdfExport;
public ActiveReportsPdfExporter()
{
_pdfExport = new PdfExport();
}
public byte[] ExportPdf(SectionReport report)
{
using (var stream = new MemoryStream())
{
_pdfExport.Export(report.Document, stream);
return stream.ToArray();
}
}
public Stream ExportPdfToStream(SectionReport report)
{
var stream = new MemoryStream();
_pdfExport.Export(report.Document, stream);
return stream;
}
}
Client Service (Angular):
(function () {
angular.module('app').factory('addressSvc', [
'$http', addressSvc
]);
function addressSvc($http) {
var service = {
printAddress: function(addressId, attentionTo, someFlag) {
var args = {
'addressId': thingId,
'attentionTo': attentionTo,
'isConfidential': isConfidential
};
return $http.get('/api/common/EnvelopeReport', { 'params': args });
}
};
return service;
}
})();
Client Controller (Angular):
(function() {
angular.module('app').controller('someCtrl', [
'$window', 'addressSvc', controller
]);
function controller($window, addressSvc) {
var vm = this;
vm.attentionTo = ''; // Bound to UI.
vm.isConfidential = ''; // Also bound to UI.
vm.address = {}; // Unimportant how we get this.
vm.printAddress = printAddress;
function printAddress() {
addressSvc.printAddress(vm.address.id, vm.attentionTo, vm.isConfidential)
.then(function(result) {
var file = new Blob([result], {type: 'application/pdf'});
var fileURL = URL.createObjectURL(file);
if(window.navigator && window.navigator.msSaveOrOpenBlob) {
window.navigator.msSaveOrOpenBlob(file, 'Envelope.pdf');
} else {
$window.open(fileURL);
}
});
}
}
)();
Question: Why is this code generating an empty PDF? I've used the Report/API Controller structure successfully in the past to generate PDFs, but usually in the context of MVC, not Web API. Another potential point of failure is the client code - I've not previously passed reports between server and client this way.
So, it turns out my server-side code was completely sane. The Client code was off.
Instead of Blobbing the data returned from the server and all of that work, what I instead needed to do was build a URL...and call $window.open(url); This is because my server code as it stands will return the PDF file as-is.

RavenDB throws a JSON deserialisation error when retrieving document

I've just completed a round of refactoring of my application, which has resulted in my removing a project that was no longer required and moving its classes into a different project. A side effect of this is that my User class, which is stored in RavenDB, has a collection property of a type moved to the new assembly. As soon as I attempt to query the session for the User class I get a Json deserialisation error. The issue is touched upon here but the answers don't address my issue. Here's the offending property:
{
"OAuthAccounts": {
"$type": "System.Collections.ObjectModel.Collection`1[
[Friendorsement.Contracts.Membership.IOAuthAccount,
Friendorsement.Contracts]], mscorlib",
"$values": []
},
}
OAuthAccounts is a collection property of User that used to map here:
System.Collections.ObjectModel.Collection`1[[Friendorsement.Contracts.Membership.IOAuthAccount, Friendorsement.Contracts]]
It now maps here:
System.Collections.ObjectModel.Collection`1[[Friendorsement.Domain.Membership.IOAuthAccount, Friendorsement.Domain]]
Friendorsement.Contracts no longer exists. All of its types are now in Friendorsement.Domain
I've tried using store.DatabaseCommands.StartsWith("User", "", 0, 128) but that didn't return anything.
I've tried looking at UpdateByIndex but not got very far with it:
store.DatabaseCommands.UpdateByIndex("Raven/DocumentsByEntityName",
new IndexQuery {Query = "Tag:Users"},
new[]
{
new PatchRequest { // unsure what to set here }
});
I'm using Raven 2.0
Below is a simple sample application that shows you the patching Metadata. While your example is a little different this should be a good starting point
namespace SO19941925
{
internal class Program
{
private static void Main(string[] args)
{
IDocumentStore store = new DocumentStore
{
Url = "http://localhost:8080",
DefaultDatabase = "SO19941925"
}.Initialize();
using (IDocumentSession session = store.OpenSession())
{
for (int i = 0; i < 10; i++)
{
session.Store(new User {Name = "User" + i});
}
session.SaveChanges();
}
using (IDocumentSession session = store.OpenSession())
{
List<User> users = session.Query<User>().Customize(x => x.WaitForNonStaleResultsAsOfNow()).ToList();
Console.WriteLine("{0} SO19941925.Users", users.Count);
}
Operation s = store.DatabaseCommands.UpdateByIndex("Raven/DocumentsByEntityName",
new IndexQuery {Query = "Tag:Users"},
new ScriptedPatchRequest
{
Script = #"this['#metadata']['Raven-Clr-Type'] = 'SO19941925.Models.User, SO19941925';"
}, true
);
s.WaitForCompletion();
using (IDocumentSession session = store.OpenSession())
{
List<Models.User> users =
session.Query<Models.User>().Customize(x => x.WaitForNonStaleResultsAsOfNow()).ToList();
Console.WriteLine("{0} SO19941925.Models.Users", users.Count);
}
Console.ReadLine();
}
}
internal class User
{
public string Name { get; set; }
}
}
namespace SO19941925.Models
{
internal class User
{
public string Name { get; set; }
}
}
UPDATE: Based on the initial answer above, here is the code that actually solves the OP question:
store.DatabaseCommands.UpdateByIndex("Raven/DocumentsByEntityName",
new IndexQuery {Query = "Tag:Users"},
new ScriptedPatchRequest
{
Script = #"this['OAuthAccounts']['$type'] =
'System.Collections.ObjectModel.Collection`1[
[Friendorsement.Domain.Membership.IFlexOAuthAccount,
Friendorsement.Domain]], mscorlib';",
}, true
);
Here are two possible solutions:
Option 1: Depending on what state your project is in, for example if you are still in development, you could easily just delete that collection out of RavenDB from the Raven Studio and recreate all those User documents. All the new User documents should then have the correct class name and assembly and should then deserialize correctly. Obviously, if you are already in production, this probably won't be a good option.
Option 2: Depending on how many User documents you have, you should be able to manually edit each one to specify the correct C# class name and assembly, so that they will be deserialized correctly. Again, if you have too many objects to manually modify, this may not be a good option; however, if there are just a few, it shouldn't be too bad to open each one up go to the metadata tab and paste the correct value for "Raven-Entity-Name" and "Raven-Clr-Type".
I ended up doing this:
Advanced.DatabaseCommands.UpdateByIndex(
"Raven/DocumentsByEntityName",
new IndexQuery {Query = "Tag:Album"},
new []{ new PatchRequest() {
Type = PatchCommandType.Modify,
Name = "#metadata",
Nested= new []{
new PatchRequest{
Name= "Raven-Clr-Type",
Type = PatchCommandType.Set,
Value = "Core.Model.Album, Core" }}}},
false);

Converting a MEF application to utilize Rx (System.Reactive)

So the current situation is I have a program that is completely utilizing MEF. Now I want to make it utilize Rx as to allow it to scale to larger queries and allow the user to look over results as the various plugins return results. It is currently setup as such:
Workflow: Query => DetermineTypes => QueryPlugins => Results
Currently the code is all stored on GitHub if anyone needs to reference more than what I post below.
ALeRT on GitHub
The VS solution has a UI project (default StartUp Project), a PluginFramework Project, various TypePlugin Projects (think determining what the type is such as a URL, Email, File, Phone Number, etc) and also QueryPlugin Projects (perform xyz if the queryplugin supports the type that has been determined). All the results are displayed back into the UI by ways of a DataGrid that is being mapped to by the DefaultView of a DataTable.
I want to try and make the Rx portion as invisible to the plugins as possible. This is due to the fact that I do not want to make writing plugins complex for the few people that will. So I was thinking about taking the current Framework below:
public interface IQueryPlugin
{
string PluginCategory { get; }
string Name { get; }
string Version { get; }
string Author { get; }
System.Collections.Generic.List<string> TypesAccepted { get; }
string Result(string input, string type, bool sensitive);
}
and making the Result method into the following:
System.IObservable<string> Result(string input, string type, bool sensitive);
This would naturally require modifying the method that is calling the plugin which as it stands is:
using (GenericParserAdapter parser = new GenericParserAdapter())
{
using (TextReader sr = new StringReader(qPlugins.Result(query, qType, sensitive)))
{
Random rNum = new Random();
parser.SetDataSource(sr);
parser.ColumnDelimiter = Convert.ToChar(",");
parser.FirstRowHasHeader = true;
parser.MaxBufferSize = 4096;
parser.MaxRows = 500;
parser.TextQualifier = '\"';
DataTable tempTable = parser.GetDataTable();
tempTable.TableName = qPlugins.Name.ToString();
if (!tempTable.Columns.Contains("Query"))
{
DataColumn tColumn = new DataColumn("Query");
tempTable.Columns.Add(tColumn);
tColumn.SetOrdinal(0);
}
foreach (DataRow dr in tempTable.Rows)
{
dr["Query"] = query;
}
if (!resultDS.Tables.Contains(qPlugins.Name.ToString()))
{
resultDS.Tables.Add(tempTable);
}
else
{
resultDS.Tables[qPlugins.Name.ToString()].Merge(tempTable);
}
pluginsLB.DataContext = resultDS.Tables.Cast<DataTable>().Select(t => t.TableName).ToList();
}
}
So at this point I'm stuck as to how to make this work. There doesn't seem to be good documentation on how to integrate MEF with Rx. My assumption is to make the following change
using (TextReader sr = new StringReader(qPlugins.Result(query, qType, sensitive).Subscribe()))
but this isn't going to work. So any help on making these changes would be greatly appreciated. If you have other suggestions regarding my code, please let me know. I do this as a hobby so I know my code surely isn't up to snuff for most people.
Would this work for you:
IObservable<DataTable> q =
from text in qPlugins.Result(query, qType, sensitive)
from tempTable in Observable.Using(
() => new GenericParserAdapter(),
parser => Observable.Using(
() => new StringReader(text),
sr => Observable .Start<DataTable>(
() =>
{
var rNum = new Random();
parser.SetDataSource(sr);
parser.ColumnDelimiter = Convert.ToChar(",");
parser.FirstRowHasHeader = true;
parser.MaxBufferSize = 4096;
parser.MaxRows = 500;
parser.TextQualifier = '\"';
var tempTable = parser.GetDataTable();
tempTable.TableName = qPlugins.Name.ToString();
if (!tempTable.Columns.Contains("Query"))
{
DataColumn tColumn = new DataColumn("Query");
tempTable.Columns.Add(tColumn);
tColumn.SetOrdinal(0);
}
foreach (DataRow dr in tempTable.Rows)
dr["Query"] = query;
return tempTable;
})))
select tempTable;

Categories