Adding attributes for faceting with Algolia C# - c#

I have an attribute that I'd like to add for faceting: ApprovalFL. When I add the facet in the Algolia dashboard, it works fine until I have to reindex which ends up deleting my facets in the dashboard for some reason. I was thinking, maybe adding the attribute in my code would resolve that. I found the documentation about this step here: https://www.algolia.com/doc/api-reference/api-parameters/attributesForFaceting/
Here's the C# example they provide:
index.SetSettings(
JObject.Parse(#"{""attributesForFaceting"":[""author"",""filterOnly(category)"",""searchable(publisher)""]}")
);
If I understand correctly, this code needs to go in my backend reindexing code (found in my AdminController.cs):
public async Task<ActionResult> ReIndexData()
{
var algoliaArtistModels = Tools.BuildAlgoliaArtistModels(EntityDataAccess.GetAllAccountInfoes());
var algoliaUnaffiliatedArtistModels = Tools.BuildAlgoliaArtistModels(EntityDataAccess.GetAllUnaffiliatedAccountInfo());
var algoliaSongModels = Tools.BuildAlgoliaSongModels(EntityDataAccess.GetAllAcceptedSongs());
var artistIndexHelper = HttpContext.Application.Get("ArtistIndexHelper") as IndexHelper<ArtistAlgoliaModel>;
var unaffiliatedArtistIndexHelper = HttpContext.Application.Get("UnaffiliatedArtist") as IndexHelper<ArtistAlgoliaModel>;
var songIndexHelper = HttpContext.Application.Get("SongIndexHelper") as IndexHelper<SongAlgoliaModel>;
await artistIndexHelper.OverwriteIndexAsync(algoliaArtistModels);
await unaffiliatedArtistIndexHelper.OverwriteIndexAsync(algoliaUnaffiliatedArtistModels);
await songIndexHelper.OverwriteIndexAsync(algoliaSongModels);
return View("AlgoliaReIndexData");
}
However, I don't think I put index.setSettings in this block of code, what is the best way to set this attribute for faceting in my backend code? The ApprovalFL attribute is stored in my Song indices.
Possibly it should go somewhere here in my Tools.cs?
public static SongAlgoliaModel BuildAlgoliaSongModel(Song song)
{
var model = new SongAlgoliaModel();
var album = EntityDataAccess.GetAlbumByID(song.AlbumID);
model.AccountImageURL = album.AccountInfo.ImageURL;
model.AccountInfoID = album.AccountInfoID;
model.AccountType = album.AccountInfo.CreatorFL == true ? "Creator" : "Artist";
model.AlbumID = song.AlbumID;
model.AlbumName = album.AlbumName;
model.ApprovalFL = song.ApprovalFL;
model.Artist = album.AccountInfo.DisplayName;
model.BPM = song.BPM;
model.Duration = song.Duration;
model.FeaturedArtist = song.Artist;
model.FreeFL = album.FreeFL;
model.ImageURL = album.ImageURL;
model.iTunesURL = album.iTunesURL;
model.LabelName = album.LabelName;
model.LicenseFL = album.LicenseFL;
model.SongID = song.SongID;
model.Title = song.Title;
model.UploadDate = song.UploadDate;
model.URL = song.URL;
model.UserID = album.AccountInfo.UserID;
return model;
}
public static List<SongAlgoliaModel> BuildAlgoliaSongModels(AccountInfo accountInfo)
{
var list = new List<SongAlgoliaModel>();
var songs = EntityDataAccess.GetSongsByUserID(accountInfo.UserID).Where(x => x.ApprovalFL == true).ToList();
foreach(var item in songs)
{
var model = new SongAlgoliaModel();
model.AccountImageURL = item.Album.AccountInfo.ImageURL;
model.AccountInfoID = item.Album.AccountInfoID;
model.AccountType = item.Album.AccountInfo.CreatorFL == true ? "Creator" : "Artist";
model.AlbumID = item.AlbumID;
model.AlbumName = item.Album.AlbumName;
model.ApprovalFL = item.ApprovalFL;
model.Artist = item.Album.AccountInfo.DisplayName;
model.BPM = item.BPM;
model.Duration = item.Duration;
model.FeaturedArtist = item.Artist;
model.FreeFL = item.Album.FreeFL;
model.ImageURL = item.Album.ImageURL;
model.iTunesURL = item.Album.iTunesURL;
model.LabelName = item.Album.LabelName;
model.LicenseFL = item.Album.LicenseFL;
model.SongID = item.SongID;
model.Title = item.Title;
model.UploadDate = item.UploadDate;
model.URL = item.URL;
model.UserID = item.Album.AccountInfo.UserID;
list.Add(model);
}
return list;
}

OK for those using C# .NET it's as simple as adding it to your Global.asax.cs for example for me:
var songIndexHelper = new IndexHelper<SongAlgoliaModel>(algoliaClient, "Song", "SongID");
songIndexHelper.SetSettings(JObject.Parse(#"{""attributesForFaceting"":[""ApprovalFL""]}"));

Why do you have to re-index by the way? Best practice is to set up your index only initially.

Related

Export csv with Async await in linq select issue

I'm currently stuck with this issue, and really got 0 ideas on how to resolve it. So I'm basically calling the export function after setting this data. Without async and dummy data It works, on implementing this, I'm not able to export anything. This is what I've done by far, and I'm not sure what I am doing wrong here. IF you have any idea, please help me. I can also provide more code if needed.
this is the code:
private async Task<IEnumerable> OnExport(SearchCriteria cr)
{
var sr = await GetResult(cr);
var results = sr.Results;
var exportData = results.Select(async export =>
{
var data = await dataService.GetById(export.Id);
var pAddress = export.ContactInformation?.Addresses.FirstOrDefault(x => x.AddressType == Framework.Contracts.Enums.AddressTypes.Physical);
var mAddress = export.ContactInformation?.Addresses.FirstOrDefault(x => x.AddressType == Framework.Contracts.Enums.AddressTypes.Mailing);
return new
{
LegalBusinessName = export.Name,
DBA = export.DBAName,
BusinessEmail = export.ContactInformation?.PrimaryEmail,
PhonePrimary = export.ContactInformation?.PrimaryPhone,
PhoneTypePrimary = export.ContactInformation?.PrimaryPhoneType,
PhoneSecondary = export.ContactInformation?.SecondaryPhone,
PhoneTypeSecondary = export.ContactInformation?.SecondaryPhoneType,
Website = export.WebAddress,
PhysicalStreetAddress = pAddress?.Address1,
PhysicalAddressLine2 = pAddress?.Address2,
PhysicalCity = pAddress?.City,
PhysicalCounty = pAddress?.County,
PhysicalState = pAddress?.State,
PhysicalZipCode = pAddress?.Zip,
MailingStreetAddress = mAddress?.Address1,
MailingAddressLine2 = mAddress?.Address2,
MailingCity = mAddress?.City,
MailingCounty = mAddress?.County,
MailingState = mAddress?.State,
MailingZipCode = mAddress?.Zip,
SchoolOnboarding = data?.ConfirmedVideo,
SchoolStartDate = data?.SchoolStartDate,
SchoolEndDate = data?.SchoolEndDate,
Grades = string.Join(",", data?.GradeLevels.Select(x => x.GradeLevel)),
IsReligiousSchool = data?.ConfirmedIsReligious,
ReligiousAffiliation = data?.ReligiousAffiliation,
TCSignatureName = export.SignatureName,
TCDateSigned = export.TermsAcceptedOn
};
});
return exportData;
}
It looks like you try to export a System.Type
Definiton of System.Type: Represents type declarations: class types, interface types, array types, value types, enumeration types, type parameters, generic type definitions, and open or closed constructed generic types.
Check if your ExportData has any value that is not a string.

XML reading - Deserialize vs XElement.Load

my question is fairly simple, which method should I use and why for parsing XML files?
Right now I have function for that:
return new EdiFile
{
SPPLR_MAILBOX = xmlDoc.Element("SPPLR_MAILBOX").Value,
MESSAGE_ID = xmlDoc.Element("MESSAGE_ID").Value,
ATTRIBUTE05 = xmlDoc.Element("ATTRIBUTE05").Value,
Levels0 = (from a in xmlDoc.Element("LEVELS0").Elements("LEVEL0")
select new Level0
{
PLT_NUM = a.Element("PLT_NUM").Value,
PLT_LABEL_ID = a.Element("PLT_LABEL_ID").Value,
BOX_QTY = a.Element("BOX_QTY").Value,
PLT_WEIGHT = a.Element("PLT_WEIGTH").Value,
PLT_DIMENSION = a.Element("PLT_DIMENSION").Value,
PLT_CHEM = a.Element("PLT_CHEM").Value,
PLT_NOT_STACK = a.Element("PLT_NOT_STACK").Value,
PLT_NOTE = a.Element("PLT_NOTE").Value,
ATTRIBUTE01 = a.Element("ATTRIBUTE01").Value,
ATTRIBUTE02 = a.Element("ATTRIBUTE02").Value,
ATTRIBUTE03 = a.Element("ATTRIBUTE03").Value,
ATTRIBUTE04 = a.Element("ATTRIBUTE04").Value,
ATTRIBUTE05 = a.Element("ATTRIBUTE05").Value,
Levels1 = (from b in a.Element("LEVELS1").Elements("LEVEL1")
select new Level1
{
BOX_NUM = b.Element("BOX_NUM").Value,
BOX_LABEL_ID = b.Element("BOX_LABEL_ID").Value,
Items = (from c in b.Element("ITEMS").Elements("ITEM")
select new Item
{
SPPLR_ITEM = c.Element("SPPLR_ITEM").Value,
CUST_ITEM = c.Element("CUST_ITEM").Value,
ATTRIBUTE01 = c.Element("ATTRIBUTE01").Value,
ATTRIBUTE02 = c.Element("ATTRIBUTE02").Value,
ATTRIBUTE03 = c.Element("ATTRIBUTE03").Value,
ATTRIBUTE04 = c.Element("ATTRIBUTE04").Value,
ATTRIBUTE05 = c.Element("ATTRIBUTE05").Value,
Lots = (from d in c.Element("LOTS").Elements("LOT")
select new Lot
{
LOT_NUM = d.Element("LOT_NUM").Value,
LOT_LABEL_ID = d.Element("LOT_LABEL_ID").Value,
LOT_NOTE = d.Element("LOT_NOTE").Value,
LOT_EXP_DATE = d.Element("LOT_EXP_DATE").Value,
QTY = d.Element("QTY").Value,
UOM = d.Element("UOM").Value,
ATTRIBUTE01 = d.Element("ATTRIBUTE01").Value,
ATTRIBUTE02 = d.Element("ATTRIBUTE02").Value,
ATTRIBUTE03 = d.Element("ATTRIBUTE03").Value,
ATTRIBUTE04 = d.Element("ATTRIBUTE04").Value,
ATTRIBUTE05 = d.Element("ATTRIBUTE05").Value
}).ToList()
}).ToList()
}).ToList()
}).ToList()
};
But should I use deserialize? I learnt about serialization yesterday.
I cant really find any source explaining my method, vs deserialization.
Can someone get me any insight please?
Your method is more performance and flexie, because you have control on processing xml file. Serialization is using reflection and it is less performance.

Return Entity Framework result as JSON

I want to get my linq query result back as json format. I have been searching for hours.
Here is my code :
public IEnumerable<callersW> GetAllCallersF()
{
testCDREntities1 context = this.CurrentDataSource;
var query = (
from oneCaller in CurrentDataSource.TestTables
select new
{
Created = oneCaller.Created,
Answered = oneCaller.Answered,
Destroyed = oneCaller.Destroyed,
CallerID = oneCaller.CallerId,
CalledID = oneCaller.CalledId,
DisconnectionCode = oneCaller.DisconnectionCode,
RTP_Caller_G107MOS = oneCaller.RTP_Caller_G107MOS,
RTP_Caller_LostPackets = oneCaller.RTP_Caller_LostPackets,
RTP_Caller_MaxRfc3550Jitter = oneCaller.RTP_Caller_MaxRfc3550Jitter,
RTP_Caller_MeanRfc3550Jitter = oneCaller.RTP_Caller_MeanRfc3550Jitter,
RTP_Called_G107MOS = oneCaller.RTP_Called_G107MOS,
RTP_Called_LostPackets = oneCaller.RTP_Called_LostPackets,
RTP_Called_MaxRfc3550Jitter = oneCaller.RTP_Called_MaxRfc3550Jitter,
RTP_Called_MeanRfc3550Jitter = oneCaller.RTP_Called_MeanRfc3550Jitter,
}).ToList()
.Select(x => new callersW
{
Created = Convert.ToDateTime(x.Created),
Answered = Convert.ToDateTime(x.Answered),
Destroyed = Convert.ToDateTime(x.Destroyed),
CallerID = x.CallerID,
CalledID = x.CalledID,
DisconnectionCode = Convert.ToInt32(x.DisconnectionCode),
RTP_Caller_G107MOS = Convert.ToDouble(x.RTP_Caller_G107MOS),
RTP_Caller_LostPackets = Convert.ToDouble(x.RTP_Caller_LostPackets),
RTP_Caller_MaxRfc3550Jitter = Convert.ToDouble(x.RTP_Caller_MaxRfc3550Jitter),
RTP_Caller_MeanRfc3550Jitter = Convert.ToDouble(x.RTP_Caller_MeanRfc3550Jitter),
RTP_Called_G107MOS = Convert.ToDouble(x.RTP_Called_G107MOS),
RTP_Called_LostPackets = Convert.ToDouble(x.RTP_Called_LostPackets),
RTP_Called_MaxRfc3550Jitter = Convert.ToDouble(x.RTP_Called_MaxRfc3550Jitter),
RTP_Called_MeanRfc3550Jitter = Convert.ToDouble(x.RTP_Called_MeanRfc3550Jitter)
}).ToList();
return query;
}
Can somebody help me with this ?
Add to your project JSON.NET and serialize object eg:
string json = JsonConvert.SerializeObject(query);
More examples here.

Testing JSON Results from MVC 4 C# Controller

So I have a controller that returns json to my views that I need to test. I have tried using reflection with a dynamic data type to access a sub property of a list but I keep getting something similar to 'unable to cast' errors. Basically I have a list within a list that I want to access and verify things about but I can't access it. Has anyone tested json returned from their controller before in MVC4 and have advice?
Code:
// arrange
var repositoryMock = new Mock<IEdwConsoleRepository>();
var date = -1;
var fromDate = DateTime.Today.AddDays(date);
EtlTableHistory[] tableHistories =
{
new EtlTableHistory
{
Table = new Table(),
RelatedStatus = new BatchStatus(),
BatchId = 1
}
};
EtlBatchHistory[] batchHistories = { new EtlBatchHistory
{
Status = new BatchStatus(),
TableHistories = tableHistories
} };
repositoryMock.Setup(repository => repository.GetBatchHistories(fromDate)).Returns((IEnumerable<EtlBatchHistory>)batchHistories);
var controller = new EdwController(new Mock<IEdwSecurityService>().Object, repositoryMock.Object);
// act
ActionResult result = controller.BatchHistories(1);
// assert
Assert.IsInstanceOfType(result, typeof(JsonResult), "Result type was incorrect");
var jsonResult = (JsonResult)result;
var resultData = (dynamic)jsonResult.Data;
var returnedHistories = resultData.GetType().GetProperty("batchHistories").GetValue(resultData, null);
var returnedTableHistoriesType = returnedHistories.GetType();
Assert.AreEqual(1, returnedTableHistoriesType.GetProperty("Count").GetValue(returnedHistories, null), "Wrong number of logs in result data");
Here's an example:
Controller:
[HttpPost]
public JsonResult AddNewImage(string buildingID, string desc)
{
ReturnArgs r = new ReturnArgs();
if (Request.Files.Count == 0)
{
r.Status = 102;
r.Message = "Oops! That image did not seem to make it!";
return Json(r);
}
if (!repo.BuildingExists(buildingID))
{
r.Status = 101;
r.Message = "Oops! That building can't be found!";
return Json(r);
}
SaveImages(buildingID, desc);
r.Status = 200;
r.Message = repo.GetBuildingByID(buildingID).images.Last().ImageID;
return Json(r);
}
public class ReturnArgs
{
public int Status { get; set; }
public string Message { get; set; }
}
Test:
[TestMethod]
public void AddNewImage_Returns_Error_On_No_File()
{
// Arrange
ExtendedBuilding bld = repo.GetBuildings()[0];
string ID = bld.Id;
var fakeContext = new Mock<HttpContextBase>();
var fakeRequest = new Mock<HttpRequestBase>();
fakeContext.Setup(cont => cont.Request).Returns(fakeRequest.Object);
fakeRequest.Setup(req => req.Files.Count).Returns(0);
BuildingController noFileController = new BuildingController(repo);
noFileController.ControllerContext = new ControllerContext(fakeContext.Object, new System.Web.Routing.RouteData(), noFileController);
// Act
var result = noFileController.AddNewImage(ID, "empty");
ReturnArgs data = (ReturnArgs)(result as JsonResult).Data;
// Assert
Assert.IsTrue(data.Status == 102);
}
In your example it looks to me that the problem is here:
var resultData = (dynamic)jsonResult.Data;
var returnedHistories = resultData.GetType().GetProperty("batchHistories").GetValue(resultData, null);
The resultData object would be the exact type of the object that you returned in your action. So if you did something like:
List<String> list = repo.GetList();
return Json(list);
Then your resultData would be of type:
List<String>
Try making sure that you are returning your Object using the Json(obj) function.
You can deserialize your Json into a dynamic object and then ask for the property you want
Example:
dynamic obj = Newtonsoft.Json.JsonConvert.DeserializeObject(json);
var propertyValue = obj.MyProperty; //Ask for the right property
You can add Json serializer from Nuget Json.Net package.

Multiple complexFilter in Magento's api v2

Currently I’m having some difficulties with using new Magento's soap v2 from c# interface.
With php i was able to do something like this:
$params["created_at"]["from"] = date("Y-m-d H:i:s",Functions::convert_time($dataDa));
$params["created_at"]["to"] = date("Y-m-d H:i:s",Functions::convert_time($dataA));
MageInterface::getSingleton()->shipmentList($params);
In this mode i was able to find list of orders which were created from $dataDa to $dataA without problems. With c# however it seems that only the last one of the selectors work.
My code:
var cpf = new complexFilter[2];
cpf[0] = new complexFilter
{
key = "created_at",
value = new associativeEntity
{
key = "to",
value = uxDataA.DateTime.ToString("yy-MM-dd HH:mm:ss")
}
});
cpf[1] = new complexFilter
{
key = "created_at",
value = new associativeEntity
{
key = "from",
value = uxDataDa.DateTime.ToString("yy-MM-dd HH:mm:ss")
}
});
var filters = new filters();
filters.complex_filter = cpf;
var risultato = mage.salesOrderList(sessionKey, filters);
In this mode only created_at->from criteria is taken in consideration (it's like second complex filter override previous one with the same key). Ideas?
Thanks in advance.
This works for me :
private filters addFilter(filters filtresIn, string key, string op, string value)
{
filters filtres = filtresIn;
if (filtres == null)
filtres = new filters();
complexFilter compfiltres = new complexFilter();
compfiltres.key = key;
associativeEntity ass = new associativeEntity();
ass.key = op;
ass.value = value;
compfiltres.value = ass;
List<complexFilter> tmpLst;
if (filtres.complex_filter!=null)
tmpLst = filtres.complex_filter.ToList();
else tmpLst = new List<complexFilter>();
tmpLst.Add(compfiltres);
filtres.complex_filter = tmpLst.ToArray();
return filtres;
}
and call
{
Mage_Api_Model_Server_V2_HandlerPortTypeClient clientSoap = new Mage_Api_Model_Server_V2_HandlerPortTypeClient();
string sessionId = clientSoap.login(LOG, PASS);
filters filtres = new filters();
filtres = addFilter(filtres, "status", "eq", "processing");
filtres = addFilter(filtres, "created_at", "from", "2014-09-07 08:00:00");
filtres = addFilter(filtres, "created_at", "to", "2014-09-07 00:00:00");
salesOrderEntity[] lst = clientSoap.salesOrderList(sessionId, filtres);
}
Solved, there was a bug (or the feature?) in mage\sales\order\api\v2.php
See more info in this thread: http://www.magentocommerce.com/boards/viewthread/70368/

Categories

Resources