In my MVC 2 application I have a typical method that calls a web service, builds a JSON data object and returns it to the view.
Everything works fine, but I was wondering if there is a way to do the mapping with Automapper so I can remove the ugly code from my controller. Thanks in advance
Here is my Action method
public virtual ActionResult AllErrors(string sidx, string sord,
int page=1, int rows=10)
{
var pageSize = rows;
var pageNumber = page;
var orderBy = string.Format("{0} {1}", sidx, sord);
var result = errorService.GetPagedOpenErrors(pageSize, page, orderBy);
var errors = new List<IngestionErrorDataContract>(result.IngestionErrors);
var totalPages = (int) Math.Ceiling(result.TotalRows/(float) pageSize);
int index = 0;
var list = new List<object>();
errors.ForEach(e => list.Add(
new {
i = index++,
cell = new[]
{
e.IngestionErrorId.ToString(),
e.RunId.ToString(),
e.ProcessDate.ToShortDateString(),
e.Status,
e.ErrorDetails
}
}));
var jsonData = new
{
total = totalPages,
page = pageNumber,
records = result.TotalRows,
rows = list.ToArray()
};
return Json(jsonData, JsonRequestBehavior.AllowGet);
}
I solved it using the ConstructUsing method of AutoMapper.
Here is my map
public void CreateMap()
{
Mapper.CreateMap<List<IngestionErrorDataContract>, object[]>()
.ConvertUsing(
errors =>
{
int index = 0;
var list = new List<object>();
errors.ForEach(e => list.Add(
new
{
i = index++,
cell = new[]
{
e.IngestionErrorId.ToString(),
e.RunId.ToString(),
e.ProcessDate.ToShortDateString(),
e.Status,
e.ErrorDetails
}
}));
return list.ToArray();
});
}
and here is my action method now
public virtual ActionResult AllErrors(string sidx, string sord, int page=1, int rows=10)
{
var pageSize = rows;
var pageNumber = page;
var orderBy = string.Format("{0} {1}", sidx, sord);
var result = errorService.GetPagedOpenErrors(pageSize, page, orderBy);
var errors = new List<IngestionErrorDataContract>(result.IngestionErrors);
var totalPages = (int) Math.Ceiling(result.TotalRows/(float) pageSize);
var jsonData = new
{
total = totalPages,
page = pageNumber,
records = result.TotalRows,
rows = mapper.Map<List<IngestionErrorDataContract>,object[]>(errors)
};
return Json(jsonData, JsonRequestBehavior.AllowGet);
}
Much better I think
Related
I'm trying to add a custom attribute to a BIM360 folder, using instructions here:
https://forge.autodesk.com/en/docs/bim360/v1/reference/http/document-management-custom-attribute-definitions-POST/
public async Task<long> addFolderCustomAttribute(string projectId, string folderId, string attributeName, string type)
{
var localVarPath = $"bim360/docs/v1/projects/{projectId.Replace("b.", "")}/folders/{System.Web.HttpUtility.UrlEncode(folderId)}/custom-attribute-definitions";
var localVarQueryParams = new Dictionary<String, String>();
Object localVarPostBody = null;
var localVarHeaderParams = new Dictionary<String, String>(Configuration.Default.DefaultHeader);
var localVarFormParams = new Dictionary<String, String>();
var localVarFileParams = new Dictionary<String, FileParameter>();
var localVarPathParams = new Dictionary<String, String>();
String[] localVarHttpContentTypes = new String[] {
"application/vnd.api+json"
};
String localVarHttpContentType = Configuration.Default.ApiClient.SelectHeaderContentType(localVarHttpContentTypes);
if (!String.IsNullOrEmpty(Configuration.Default.AccessToken))
{
localVarHeaderParams["Authorization"] = "Bearer " + Configuration.Default.AccessToken;
}
localVarPostBody = "{\"name\":\"" + attributeName + "\", \"type\":\"" + type + "\"}";
IRestResponse localVarResponse = (IRestResponse)await Configuration.Default.ApiClient.CallApiAsync(localVarPath,
Method.POST, localVarQueryParams, localVarPostBody, localVarHeaderParams, localVarFormParams, localVarFileParams,
localVarPathParams, localVarHttpContentType);
int localVarStatusCode = (int)localVarResponse.StatusCode;
var response = new ApiResponse</*JsonApiCollection*/dynamic>(localVarStatusCode,
localVarResponse.Headers.ToDictionary(x => x.Name, x => x.Value.ToString()),
/*(JsonApiCollection)*/ Configuration.Default.ApiClient.Deserialize(localVarResponse, typeof(JsonApiCollection)));
var id = (long)((Autodesk.Forge.Model.DynamicJsonResponse)response.Data).Dictionary["id"];
return id;
}
And I receive this error: CUSTOM_ATTRIBUTE_DUPLICATE_NAME
however when I enumerate the folder's custom attributes using:
https://forge.autodesk.com/en/docs/bim360/v1/reference/http/document-management-custom-attribute-definitions-GET/
public async Task<Dictionary<long, Tuple<string, string>>> getFolderCustomAttributeDefinition(string projectId, string folderId)
{
var localVarPath = $"bim360/docs/v1/projects/{projectId.Replace("b.", "")}/folders/{System.Web.HttpUtility.UrlEncode(folderId)}/custom-attribute-definitions";
var localVarQueryParams = new Dictionary<String, String>();
Object localVarPostBody = null;
var localVarHeaderParams = new Dictionary<String, String>(Configuration.Default.DefaultHeader);
var localVarFormParams = new Dictionary<String, String>();
var localVarFileParams = new Dictionary<String, FileParameter>();
var localVarPathParams = new Dictionary<String, String>();
String[] localVarHttpContentTypes = new String[] {
"application/vnd.api+json"
};
String localVarHttpContentType = Configuration.Default.ApiClient.SelectHeaderContentType(localVarHttpContentTypes);
if (!String.IsNullOrEmpty(Configuration.Default.AccessToken))
{
localVarHeaderParams["Authorization"] = "Bearer " + Configuration.Default.AccessToken;
}
IRestResponse localVarResponse = (IRestResponse) await Configuration.Default.ApiClient.CallApiAsync(localVarPath,
Method.GET, localVarQueryParams, localVarPostBody, localVarHeaderParams, localVarFormParams, localVarFileParams,
localVarPathParams, localVarHttpContentType);
int localVarStatusCode = (int)localVarResponse.StatusCode;
var response = new ApiResponse</*JsonApiCollection*/dynamic>(localVarStatusCode,
localVarResponse.Headers.ToDictionary(x => x.Name, x => x.Value.ToString()),
/*(JsonApiCollection)*/ Configuration.Default.ApiClient.Deserialize(localVarResponse, typeof(JsonApiCollection)));
var sret = ((Autodesk.Forge.Model.DynamicJsonResponse)response.Data).Dictionary["results"];
var resultsDic = ((Autodesk.Forge.Model.DynamicDictionary)sret).Dictionary;
Dictionary<long, Tuple<string, string>> ret = new Dictionary<long, Tuple<string, string>>();
foreach (var att in resultsDic) {
var attrDic = (Autodesk.Forge.Model.DynamicDictionary)att.Value;
ret.Add((long)attrDic.Dictionary["id"], new Tuple<string, string>((string)attrDic.Dictionary["name"], (string)attrDic.Dictionary["type"]));
}
return ret;
}
It does not show any attribute with that name.
Any ideas?
I am using CsvHelper I need to wrap all values with quotes.
Is that possible?
Data = is a List
using (StreamWriter textWriter = new StreamWriter(path))
{
textWriter.BaseStream.Write(p, 0, p.Length);
// var dt = new DataTable();
var csv = new CsvWriter(textWriter);
csv.WriteRecords(Data);
textWriter.Flush();
textWriter.Close();
}
Thanks
There is a config value called ShouldQuote where you can determine on a field level if it should be quoted.
void Main()
{
var records = new List<Foo>
{
new Foo { Id = 1, Name = "one" },
new Foo { Id = 2, Name = "two" },
};
using (var writer = new StringWriter())
using (var csv = new CsvWriter(writer))
{
csv.Configuration.ShouldQuote = (field, context) => true;
csv.WriteRecords(records);
writer.ToString().Dump();
}
}
public class Foo
{
public int Id { get; set; }
public string Name { get; set; }
}
Output:
"Id","Name"
"1","one"
"2","two"
From version 25.0.0 up to the date, the way of doing it is:
var config = new CsvConfiguration(CultureInfo.InvariantCulture)
{
ShouldQuote = args => true
};
Just need to add a configuration object. like this
CsvHelper.Configuration.CsvConfiguration config = new CsvHelper.Configuration.CsvConfiguration();
config.QuoteAllFields = true;
var csv = new CsvWriter(textWriter, config);
I have parsed the feed http://www.toucheradio.com/toneradio/android/toriLite/AndroidRSS.xml
And all items from rss feed displayed in listbox.Now I dont want to get first item I have to omit it.How Can I do it.
MainPage.xaml.cs:
namespace tori
{
public partial class MainPage : PhoneApplicationPage
{
// Constructor
public MainPage()
{
InitializeComponent();
// is there network connection available
if (!System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable())
{
MessageBox.Show("No network connection available!");
return;
}
// start loading XML-data
WebClient downloader = new WebClient();
Uri uri = new Uri(" http://www.toucheradio.com/toneradio/android/toriLite/AndroidRSS.xml", UriKind.Absolute);
downloader.DownloadStringCompleted += new DownloadStringCompletedEventHandler(ChannelDownloaded);
downloader.DownloadStringAsync(uri);
}
void ChannelDownloaded(object sender, DownloadStringCompletedEventArgs e)
{
if (e.Result == null || e.Error != null)
{
MessageBox.Show("There was an error downloading the XML-file!");
}
else
{
// Deserialize if download succeeds
XDocument document = XDocument.Parse(e.Result);
var queue = from item in document.Descendants("item")
select new Item
{
title = item.Element("title").Value
,
link = item.Element("link").Value
,
ThumbnailUrl = item.Element(item.GetNamespaceOfPrefix("media") + "thumbnail").Attribute("url").Value
,
};
itemsList.ItemsSource = queue;
}
}
public class Item
{
public string title { get; set; }
public string ThumbnailUrl { get; set; }
public string link { get; set; }
}
If I write queue.RemoveAt(0);
i was getting error at RemoveAt.
Can anybody please tell me how can I do that.
Many Thanks in advance.
You can easily do this using LINQ Skip extension method (documentation here).
Just try the sample below:
itemsList.ItemsSource = queue.Skip(1);
As well you can rewrite the query to omit the first item before applying the projection in the select method using the methods chain approach:
var queue = document.Descendants("item")
.Skip(1)
.Select(item => new Item
{
title = item.Element("title").Value,
link = item.Element("link").Value,
ThumbnailUrl = item.Element(item.GetNamespaceOfPrefix("media") + "thumbnail").Attribute("url").Value,
})
.ToList();
itemsList.ItemsSource = queue;
UPDATE / DUE TO COMMENTS
And as well if you need to skip items at certain indexes you may use the Where method and the HasSet as in the sample below:
var document = XDocument.Parse(e.Result);
var indexes = new HashSet<int> { 1, 3, 4 };
var queue = document.Descendants("item")
.Select(item => new Item
{
title = item.Element("title").Value,
link = item.Element("link").Value,
ThumbnailUrl =
item.Element(item.GetNamespaceOfPrefix("media") + "thumbnail").Attribute("url").Value,
})
.Where((x, i) => !indexes.Contains(i))
.ToList();
Items.ItemsSource = queue;
I am struggling to successfully implement a POST operation within Windows Phone 8.1.
PostMessage method executes without any exceptions being caught.
However, the POST method within MessagesController never gets invoked.
How do I perform a POST for Windows Phone 8.1?
The code is below:
internal async Task PostMessage(string text)
{
Globals.MemberId = 1;
int memberId = 2;
// server to POST to
string url = #"http://localhost:17634/api/messages";
try
{
// HTTP web request
var httpWebRequest = (HttpWebRequest)WebRequest.Create(url);
httpWebRequest.ContentType = "text/plain; charset=utf-8";
httpWebRequest.Method = "POST";
// Write the request Asynchronously
using (var stream = await Task.Factory.FromAsync<Stream>(httpWebRequest.BeginGetRequestStream,
httpWebRequest.EndGetRequestStream, null))
{
//create some json string
var message = new Message() { FromId = Globals.MemberId, ToId = memberId, Content = text, Timestamp = DateTime.Now };
var json = string.Format("{0}{1}", "action=", JsonConvert.SerializeObject(message));
// convert json to byte array
byte[] jsonAsBytes = Encoding.UTF8.GetBytes(json);
// Write the bytes to the stream
await stream.WriteAsync(jsonAsBytes, 0, jsonAsBytes.Length);
}
}
catch(Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
public class MessagesController : ApiController
{
public HttpResponseMessage Post(Message message)
{
throw new NotImplementedException();
}
}
public class Message
{
public int MessageId { get; set; }
public int FromId { get; set; }
public int ToId { get; set; }
public DateTime Timestamp { get; set; }
public string Content { get; set; }
}
The following link resolved my issue.
The updated client is as follows:
using (var client = new System.Net.Http.HttpClient())
{
// New code:
client.BaseAddress = new Uri(Globals.URL_PREFIX);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var message = new Message() { MessageId = 0, FromId = Globals.MemberId, ToId = memberId, Content = text, Timestamp = DateTime.Now };
var json_object = JsonConvert.SerializeObject(message);
var response = await client.PostAsync("api/messages", new StringContent(json_object.ToString(), Encoding.UTF8, "application/json"));
Debug.Assert(response.StatusCode == System.Net.HttpStatusCode.Accepted);
}
This works fine for me. The function accepts an payload of type T. The server accepts a JSON object and returns a JSON response.
public async static Task SendRequestPacket<T>(object payload)
{
Uri theUri = new Uri("the_uri");
//Create an Http client and set the headers we want
HttpClient aClient = new HttpClient();
aClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
aClient.DefaultRequestHeaders.Host = theUri.Host;
//Create a Json Serializer for our type
DataContractJsonSerializer jsonSer = new DataContractJsonSerializer(typeof(T));
// use the serializer to write the object to a MemoryStream
MemoryStream ms = new MemoryStream();
jsonSer.WriteObject(ms, payload);
ms.Position = 0;
//use a Stream reader to construct the StringContent (Json)
StreamReader sr = new StreamReader(ms);
StringContent theContent = new StringContent(sr.ReadToEnd(), Encoding.UTF8, "application/json");
//Post the data
HttpResponseMessage aResponse = await aClient.PostAsync(theUri, theContent);
if (aResponse.IsSuccessStatusCode)
{
string content = await aResponse.Content.ReadAsStringAsync();
System.Diagnostics.Debug.WriteLine(content);
}
else
{
// show the response status code
}
}
Just dont use HttpWebRequest if you are not forced to in any way.
This example is using HttpClient() and it is good to always have the client created once and not every time you make a request.
So in your class add:
private static HttpClient _client;
public static Uri ServerBaseUri
{
get { return new Uri("http://localhost:17634/api"); }
}
public ClassConstructor()
{
_client = new HttpClient();
}
internal async Task<ResponseType> PostMessage(string text)
{
Globals.MemberId = 1;
int memberId = 2;
try
{
var js = "{ JSON_OBJECT }";
var json = new StringContent(js);
json.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json");
var response = await Client.PostAsync(new Uri(ServerBaseUri, "/messages"), json);
var reply = await response.Content.ReadAsStringAsync();
} catch (Exception)
{
return null;
}
}
More on HttpClient.
I'm new to windows phone development. I'm trying to delete selected item from the list box. I've got dataclass
public class MyDataClass
{
public string MSG { get; set; }
public int Id { get; set; }
}
Then I try to delete the selected item (Button1_Click event)
MyDataClass item = MyDict.SelectedItem as MyDataClass;
ObservableCollection dataList = new ObservableCollection();
dataList.Remove(item);
The problem in creating the datalist in task, so it's no availble for the rest of the program, how to change this?
public async Task GETFROMDB()
{
int a = 1;
Database database = new Database(ApplicationData.Current.LocalFolder, "DictData.db");
await database.OpenAsync();
string query = "SELECT * FROM MyDICT";
Statement statement = await database.PrepareStatementAsync(query);
statement.EnableColumnsProperty();
ObservableCollection<MyDataClass> dataList = new ObservableCollection<MyDataClass>();
while (await statement.StepAsync())
{
rawData = string.Format(statement.Columns["value"]);
string[] sep = new string[] { "\r\n" }; //Splittng it with new line
string[] arrData = rawData.Split(sep, StringSplitOptions.RemoveEmptyEntries);
foreach (var d in arrData)
{
dataList.Add(new MyDataClass() { MSG = d, Id= a });
a++;
}
}
MyDict.ItemsSource = dataList;
}
Can you make binding to a dataList outside the Task and make dataList static or reference to it in a Task?
When creating a list:
static ObservableCollection<MyDataClass> dataList = new ObservableCollection<MyDataClass>();
MyDict.ItemsSource = dataList;
Then in Task:
public async Task GETFROMDB()
{
int a = 1;
Database database = new Database(ApplicationData.Current.LocalFolder, "DictData.db");
await database.OpenAsync();
string query = "SELECT * FROM MyDICT";
Statement statement = await database.PrepareStatementAsync(query);
statement.EnableColumnsProperty();
while (await statement.StepAsync())
{
rawData = string.Format(statement.Columns["value"]);
string[] sep = new string[] { "\r\n" }; //Splittng it with new line
string[] arrData = rawData.Split(sep, StringSplitOptions.RemoveEmptyEntries);
foreach (var d in arrData)
{
dataList.Add(new MyDataClass() { MSG = d, Id= a });
a++;
}
}
}
Then in Click:
MyDataClass item = MyDict.SelectedItem as MyDataClass;
dataList.Remove(item);
Or make it:
When creating a list:
ObservableCollection<MyDataClass> dataList = new ObservableCollection<MyDataClass>();
MyDict.ItemsSource = dataList;
Then in Task:
public async Task GETFROMDB(ObservableCollection<MyDataClass> dataList)
{
int a = 1;
Database database = new Database(ApplicationData.Current.LocalFolder, "DictData.db");
await database.OpenAsync();
string query = "SELECT * FROM MyDICT";
Statement statement = await database.PrepareStatementAsync(query);
statement.EnableColumnsProperty();
while (await statement.StepAsync())
{
rawData = string.Format(statement.Columns["value"]);
string[] sep = new string[] { "\r\n" }; //Splittng it with new line
string[] arrData = rawData.Split(sep, StringSplitOptions.RemoveEmptyEntries);
foreach (var d in arrData)
{
dataList.Add(new MyDataClass() { MSG = d, Id= a });
a++;
}
}
}
Then in Click:
MyDataClass item = MyDict.SelectedItem as MyDataClass;
dataList.Remove(item);
Of course you need to wait until the Task is finished.
you appear to be trying to remove the item from a brand new collection - try instead to remove it from the one that your listbox is data bound to.
Try using the button data context
like this
in your click handler
private void ButtonClick(object sender, RoutedEventArgs e)
{
Button btn = sender as Button;
if (btn != null)
{
MyDataClass item = btn.DataContext as MyDataClass;
dataList.Remove(item);
}
}